Android Practical Beauty jigsaw puzzle game you can stick to the level, android jigsaw puzzle game

Source: Internet
Author: User

Android Practical Beauty jigsaw puzzle game you can stick to the level, android jigsaw puzzle game
Reprinted please indicate the source: bytes

After 2048, today we will bring you a puzzle game. Of course, it is not a traditional one that lacks one piece of the puzzle, so I won't play it ~~ How can we play the puzzle in another way? Make a lot of images and combine them into a complete one. In this way, the level is easy to design, such as 3*3; 4*4; 5*5; 6*6 ;... keep going ....

The reason why a blog is generated is that it is okay to visit the Internet to see an auxiliary class for image slicing. The class is very simple. I mentioned above, it can be used for a puzzle game. Then, so we can use ~~

The effect is as follows:

A switching animation is added, and the effect is good ~~ In fact, the game is a custom control. Next we will start the custom journey ~~

2. Game Design

First, we will analyze how to design this game:

1. We need a container to store the blocks of these images. For convenience, we are going to use RelativeLayout with addRule.

2. For each block of an image, use ImageView.

3. Click exchange. We are going to use the traditional TranslationAnimation for implementation.

With preliminary design, I feel this game is so easy ~

3. Implementation of game Layout

First, we are prepared to cut an image into n x n parts and place it in the specified position;

We only need to set the number n, and then divide by n Based on the small value of the layout width or height, minus some margins to get the width and height of our ImageView ~~

1. constructor:

/*** Set the number of items n * n. The default value is 3 */private int mColumn = 3;/*** layout width */private int mWidth; /* layout padding */private int mPadding;/* stores all items */private ImageView [] mGamePintuItems; /*** Item width */private int mItemWidth;/*** horizontal and vertical margin of the Item */private int mMargin = 3; /***** the image of the puzzle */private Bitmap mBitmap;/***** stores the image beans after the cut */private List <ImagePiece> mItemBitmaps; private boolean once; public GamePintuLayout (Context context) {this (context, null);} public GamePintuLayout (Context context, AttributeSet attrs) {this (context, attrs, 0 );} public GamePintuLayout (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle); mMargin = (int) TypedValue. applyDimension (TypedValue. COMPLEX_UNIT_DIP, mMargin, getResources (). getDisplayMetrics (); // set the padding of Layout. The four sides are the same. Set it to the minimum value of the four padding mPadding = min (getPaddingLeft (), getPaddingTop (), getPaddingRight (), getPaddingBottom ());}

In the constructor, we get to convert the set margin value to dp; get the layout padding value; the whole is a square, so we take the minimum value in the four directions of padding;

As for margin, as the horizontal and vertical spacing between items, you can select Custom Attributes if you like ~~

2. onMeasure

@ Overrideprotected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec); // obtain the edge length of the game layout. mWidth = Math. min (getMeasuredHeight (), getMeasuredWidth (); if (! Once) {initBitmap (); initItem () ;}once = true; setMeasuredDimension (mWidth, mWidth );}

OnMeasure mainly obtains the layout width, prepares the image, initializes our Item, and sets the width and height for the Item.

InitBitmap is naturally used to prepare images:

private void initBitmap(){if (mBitmap == null)mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.aa);mItemBitmaps = ImageSplitter.split(mBitmap, mColumn);Collections.sort(mItemBitmaps, new Comparator<ImagePiece>(){@Overridepublic int compare(ImagePiece lhs, ImagePiece rhs){return Math.random() > 0.5 ? 1 : -1;}});}

If no mBitmap is set here, we will prepare a backup image, and then call ImageSplitter. split to cut the image into n x n and return a List <ImagePiece>

After splitting, We need to disrupt the order, so we call the sort method. As for the comparator, we use random to randomly compare the size ~~ In this way, our unordered operations are completed ~~

Public class ImageSplitter {/*** cut the image into pieces. piece * piece ** @ param bitmap * @ param piece * @ return */public static List <ImagePiece> split (Bitmap bitmap, int piece) {List <ImagePiece> pieces = new ArrayList <ImagePiece> (piece * piece); int width = bitmap. getWidth (); int height = bitmap. getHeight (); Log. e ("TAG", "bitmap Width =" + width + ", height =" + height); int pieceWidth = Math. min (width, height)/piece; for (int I = 0; I <piece; I ++) {for (int j = 0; j <piece; j ++) {ImagePiece imagePiece = new ImagePiece (); imagePiece. index = j + I * piece; int xValue = j * pieceWidth; int yValue = I * pieceWidth; imagePiece. bitmap = Bitmap. createBitmap (bitmap, xValue, yValue, pieceWidth, pieceWidth); pieces. add (imagePiece) ;}} return pieces ;}}

public class ImagePiece{public int index = 0;public Bitmap bitmap = null;}

What I did not say is a process of cutting and saving the Graph Based on the width and height, and n ~~

ImagePiece: saved images and indexes ~~ I discovered these two classes on the Internet ~~

The image is ready now. Now we can see that the width and height of Item generation have been set, that is, initItems.

Private void initItem () {// get the width of the Item int childWidth = (mWidth-mPadding * 2-mMargin * (mColumn-1)/mColumn; mItemWidth = childWidth; mGamePintuItems = new ImageView [mColumn * mColumn]; // place Itemfor (int I = 0; I <mGamePintuItems. length; I ++) {ImageView item = new ImageView (getContext (); item. setOnClickListener (this); item. setImageBitmap (mItemBitmaps. get (I ). bitmap); mGamePintuItems [I] = item; item. se TId (I + 1); item. setTag (I + "_" + mItemBitmaps. get (I ). index); RelativeLayout. layoutParams lp = new LayoutParams (mItemWidth, mItemWidth); // sets the horizontal margin, not the last column if (I + 1) % mColumn! = 0) {lp. rightMargin = mMargin;} // if it is not the first column if (I % mColumn! = 0) {lp. addRule (RelativeLayout. RIGHT_OF, // mGamePintuItems [I-1]. getId ();} // if it is not the first row, // set the vertical margin, if (I + 1)> mColumn) {lp. topMargin = mMargin; lp. addRule (RelativeLayout. BELOW, // mGamePintuItems [I-mColumn]. getId ();} addView (item, lp );}}

We can see the calculation of the Item width: childWidth = (mWidth-mPadding * 2-mMargin * (mColumn-1)/mColumn;

Container width, excluding its own padding, excluding the spacing between items, and then divided by the number of items in a row to get the width of the Item ~~

Next, we will traverse and generate items, set Rule based on their locations, and carefully read the annotations ~~


We set setOnClickListener for Item. Of course, this is because our game just clicks Item ~

We also set Tag for Item: item. setTag (I + "_" + mItemBitmaps. get (I). index );

The tag contains the index, which is the correct position. I, I can help us find the current Item image in mItemBitmaps: (mItemBitmaps. get (I). bitmap)

At this point, the layout code of our game is over ~~~

Then we declare in the layout file:

<RelativeLayout xmlns:android=""    xmlns:tools=""    android:layout_width="fill_parent"    android:layout_height="fill_parent" >    <com.zhy.gamePintu.view.GamePintuLayout        android:id="@+id/id_gameview"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:layout_centerInParent="true"        android:padding="5dp" >    </com.zhy.gamePintu.view.GamePintuLayout></RelativeLayout>

Remember to set the layout in the Activity ~~

The effect is as follows:

I changed a landscape map, and it was quite refreshing ~~ The layout of our cut chart has been completed, isn't it very simple? And we feel that our game has completed more than half of it ~~~ The rest is nothing more than processing the click of an Item.

4. Game Switching Effect
1. Initial switchover

Do you still remember that we added the onClick listener to Item ~~

Now we need to implement it. Click two items and their images can be exchanged ~

Then, we need two member variables to store the two items and then exchange them.

Private ImageView mFirst; private ImageView mSecond; @ Overridepublic void onClick (View v) {/*** if the two clicks are the same */if (mFirst = v) {mFirst. setColorFilter (null); mFirst = null; return;} // click the first Itemif (mFirst = null) {mFirst = (ImageView) v; mFirst. setColorFilter (Color. parseColor ("#55FF0000");} else // click the second Item {mSecond = (ImageView) v; exchangeView ();}}

Click the first one, set the selected effect through setColorFilter, and click the other one again. Then we are ready to call exchangeView to exchange images. Of course, we haven't written this method yet ~

If you click the same one twice to remove the selected effect, nothing will happen.

Next, we will implement the exchangeView:

/*** Swap two Item images */private void exchangeView () {mFirst. setColorFilter (null); String firstTag = (String) mFirst. getTag (); String secondTag = (String) mSecond. getTag (); // obtain the index position String [] firstImageIndex = firstTag in the list. split ("_"); String [] secondImageIndex = secondTag. split ("_"); mFirst. setImageBitmap (mItemBitmaps. get (Integer. parseInt (secondImageIndex [0]). bitmap); mSecond. setImageBitmap (mItemBitmaps. get (Integer. parseInt (firstImageIndex [0]). bitmap); mFirst. setTag (secondTag); mSecond. setTag (firstTag); mFirst = mSecond = null ;}
Remember our previous setTag. Forget to go back and check it out. We also want to pay attention to it ~

Through getTag, the index is obtained in the List, bitmap is obtained for switching settings, and finally the tag is exchanged;

At this point, our exchange effect is finished, and our game is finished ~~ The effect is as follows:

We can see that we are ready to play ~~~ Why don't you use a fresh Landscape Map? It's because you can't see the pair ~

I'm sure everyone will talk about it. I will wipe it, And I will switch the animation. Isn't it clearly two flying past exchanges? What is Nima ~~~

Also, we need to pursue it with the program. Next we will add the animation switching effect ~~

2. Seamless animation Switching

Let's talk about how to add them first. I'm going to use TranslationAnimation, and then the top and left of the two items are also obtained by containers;

However, we need to understand that, in fact, the Item is only setImage, and the position of the Item is not changed;

Now we need to move the animation effect, such as moving A to B. It's okay. After moving it, we have to go back to the Item, but the image hasn't changed. We still need to manually setImage

This has resulted in an animation switching effect, but there will still be a flash in the end, because we switched the image;

In order to avoid the above phenomenon and achieve the perfect switching effect, we introduce an animation layer dedicated to the animation effect, which is a bit similar to the ps layer. Let's see how we do it;

/*** Animation running flag */private boolean isAniming;/***** animation Layer */private RelativeLayout mAnimLayout; /*** swap two Item images */private void exchangeView () {mFirst. setColorFilter (null); setUpAnimLayout (); // Add FirstViewImageView first = new ImageView (getContext (); first. setImageBitmap (mItemBitmaps. get (getImageIndexByTag (String) mFirst. getTag ())). bitmap); LayoutParams lp = new LayoutParams (mItemWidth, mItemWidth); lp. leftMargin = mFirst. getLeft ()-mPadding; lp. topMargin = mFirst. getTop ()-mPadding; first. setLayoutParams (lp); mAnimLayout. addView (first); // Add SecondViewImageView second = new ImageView (getContext (); second. setImageBitmap (mItemBitmaps. get (getImageIndexByTag (String) mSecond. getTag ())). bitmap); LayoutParams lp2 = new LayoutParams (mItemWidth, mItemWidth); lp2.leftMargin = mSecond. getLeft ()-mPadding; lp2.topMargin = mSecond. getTop ()-mPadding; second. setLayoutParams (lp2); mAnimLayout. addView (second); // set the animated TranslateAnimation anim = new TranslateAnimation (0, mSecond. getLeft ()-mFirst. getLeft (), 0, mSecond. getTop ()-mFirst. getTop (); anim. setDuration (1, 300); anim. setFillAfter (true); first. startAnimation (anim); TranslateAnimation animSecond = new TranslateAnimation (0, mFirst. getLeft ()-mSecond. getLeft (), 0, mFirst. getTop ()-mSecond. getTop (); animSecond. setDuration (300); animSecond. setFillAfter (true); second. startAnimation (animSecond); // Add an animation listener anim. setAnimationListener (new AnimationListener () {@ Overridepublic void onAnimationStart (Animation animation) {isAniming = true; mFirst. setVisibility (INVISIBLE); mSecond. setVisibility (INVISIBLE) ;}@ Overridepublic void onAnimationRepeat (Animation animation) {}@ Overridepublic void onAnimationEnd (Animation animation) {String firstTag = (String) mFirst. getTag (); String secondTag = (String) mSecond. getTag (); String [] firstParams = firstTag. split ("_"); String [] secondParams = secondTag. split ("_"); mFirst. setImageBitmap (mItemBitmaps. get (Integer. parseInt (secondParams [0]). bitmap); mSecond. setImageBitmap (mItemBitmaps. get (Integer. parseInt (firstParams [0]). bitmap); mFirst. setTag (secondTag); mSecond. setTag (firstTag); mFirst. setVisibility (VISIBLE); mSecond. setVisibility (VISIBLE); mFirst = mSecond = null; mAnimLayout. removeAllViews (); // checkSuccess (); isAniming = false ;}});}/*** create an animation Layer */private void setUpAnimLayout () {if (mAnimLayout = null) {mAnimLayout = new RelativeLayout (getContext (); addView (mAnimLayout) ;}} private int getImageIndexByTag (String tag) {String [] split = tag. split ("_"); return Integer. parseInt (split [0]);}

When switching, we create an animation layer, add two identical items on this layer, hide the original items, and perform animation switching. setFillAfter is true ~

After the animation is completed, we have quietly exchanged the image of the Item and displayed it directly. In this way, the switchover is perfect:

General process:

1. Hide A and B

2. the animation of copy A moves to the position of copy B, and the animation of copy B moves to the position of copy.

3. A sets the image to B, removes the copy B, and displays A. This perfectly fits the situation and the user feels B is moving.

4. Same as B

Our results:

Now the effect is satisfactory ~~ To prevent user madness, add one sentence in onClick:

@ Overridepublic void onClick (View v) {// if an animation is being executed, shield if (isAniming) return;

At this point, our animation switching has ended perfectly ~~

Should we determine whether the switchover is successful ~~

5. Game victory judgment

After the switchover is complete, we can determine the checkSuccess (); fortunately, we have placed the correct order of the image in the tag ~~

/*** Determine whether the game is successful */private void checkSuccess () {boolean isSuccess = true; for (int I = 0; I <mGamePintuItems. length; I ++) {ImageView first = mGamePintuItems [I]; Log. e ("TAG", getIndexByTag (String) first. getTag () + ""); if (getIndexByTag (String) first. getTag ())! = I) {isSuccess = false ;}} if (isSuccess) {Toast. makeText (getContext (), "Success, Level Up! ", Toast. LENGTH_LONG ). show (); // nextLevel () ;}}/*** obtain the true index of the image * @ param tag * @ return */private int getIndexByTag (String tag) {String [] split = tag. split ("_"); return Integer. parseInt (split [1]);}

It's easy to traverse all items, get the real index based on the Tag, and compare it with the order of course. If it is the same, it will win ~~ After the victory, enter the next level.

The following code is used:

public void nextLevel(){this.removeAllViews();mAnimLayout = null;mColumn++;initBitmap();initItem();}

OK. Now our game is over. I will take you through the following steps:

Deliberately leave a step for me to level up ~~ We hope that both the game and the technology can be up !!!

Due to space limitations, time restrictions, and display, you will not be taken into consideration. If you feel it is necessary, add it as needed ~~

Download source code

I have created a QQ Group for your convenience. Group Number:55032675

Bytes ----------------------------------------------------------------------------------------------------------

Some of the bloggers have already been online. If you do not like boring text, stamp it (for initial record, we look forward to your support ):

1. High imitation 5.2.1 main interface and message reminder

2. High imitation QQ5.0 slide

How can I complete a puzzle in an android puzzle game?

Specify an attribute for each image and store its location identifier. When all the Image Location identifiers meet the victory condition, the puzzle is completed.

Beauty puzzle games

Not understand

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.