Step by Step Guide on How to Build a Slider PICTURE puzzle game using cocos2d for android

A picture slider puzzle is definitely the next best thing after a number slider puzzle or an alphabet slider puzzle. And that’s what we would be building in this tutorial post.

Note : This post builds on previous tutorials for building a slider puzzle game using cocos2d for android. Its important you review the earlier parts as we build on code and concepts discussed there.

How do we make a picture puzzle.

In our slider puzzle, for each tile, we have a background image (tile.png) which we assign to each tile. How about we make 9 different tile.png images and assign them to each tile such that when  arranged, they form a complete picture ? Time consuming (creating 9 different images) an not very scalable (e.g if we need to create a 5 x 5 slider puzzle or if we need to change the image .. etc). A workable but not scalable solution .

What if we could dynamically break a single image into bits and add its bit to each tile ? Turns out we can do that using Cocos2D 2D Textures and that’s how we are going to implement this solution. In our slider puzzle code we already create nodes  and  assign tile.png sprites as the background of these nodes. Now, instead we dynamically create sprite images as portions of  a larger image in our asset folder and assign these portions to a node in a new for loop. We do all of this by improving our “generateTiles” method.

benin

We have a single image above and we assign portions of it as the background image of each tile.

Step 1.  Create a bitmap from the image of choice

Bitmap mybit = null;
try {
mybit = getBitmapFromAsset("benin.jpg");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

We add the getBitmapFromAsset function to our class

private Bitmap getBitmapFromAsset(String strName) throws IOException
{
AssetManager assetManager = CCDirector.sharedDirector().getActivity().getAssets();

InputStream istr = assetManager.open(strName);
Bitmap bitmap = BitmapFactory.decodeStream(istr);

return bitmap;
}

Note: we have to add benin.jpg to our assets folder. You may replace this image with your own image of choice.

Step 2  Create a 2D texture and initialize it using the created bitmap.

CCTexture2D metexture = new CCTexture2D();
metexture.initWithImage(mybit);

Step 3 Create new sprite from a portion of the texture and assign to tile

Next , create a new sprite from this texture which is a subset of the entire image and assign that to a tile. Essentially we break the picture into smaller bits (spriteframes) and assign them to different tiles. If you have followed the tutorial thus far, you’ll be familiar with basic math used to calculate the size of each tile and the associated for loops (x and y cordinates) used “move” through parts of an image. We draw on that thought process again and use “for loops” to break a given image into bits.

int rowindex = 0 ;
for (float j = 0 ; j < NUM_ROWS ; j++){
for (float i = 0 ; i <NUM_COLUMNS; i++){

//Calculate the size of each tile by dividing the height and width of our image
// and returning the min value of both calculations
float theblock = Math.min( mybit.getHeight()/NUM_ROWS, mybit.getWidth()/NUM_COLUMNS) ;

//Create a new sprite using this dimension above and from a given portion of the image
CCSpriteFrame myframe = CCSpriteFrame.frame(metexture, CGRect.make(i*theblock, j*theblock, theblock, theblock), CGPoint.make(0, 0));
tile = CCSprite.sprite(myframe);
tile.setScale((TILE_SQUARE_SIZE/theblock) * (1.3f*scalefactor));

//Assign our newly created sprite background to a node created earlier.
tileNode.getChildByTag(nodeindex).addChild(tile,-1,1);
tileNode.setContentSize(tile.getContentSize());

if(nodeindex == (NUM_ROWS * NUM_COLUMNS) - 1){
break ;
}
nodeindex++ ;
}
}

Next Steps

– Improve the code such that rather than using static files in the assets folder, users can select images from the device gallery or from camera.
Hint : Use the android gallery intent to launch the gallery widget and get the selected image as a bitmap. Create a function getBitMapFromGallery that returns this selected image.
– Improve the run time of the solution above .
Hint : Combine the two For Loops used . Currently we use two sets of For loops. The first only sets up the empty tiles based on our previous tutorials. The second one generates the new background sprite images from our bitmap and assigns them to the empty tiles. Find a clever way to combine both loops.
– Add a hint button for players to view the complete picture.
– Increase difficulty by removing the numbers on the tiles.

Gimme that Updated Code!

As usual, the updated project on can be downloaded from github. What are your thoughts on the solution we have adopted in developing the picture slider puzzle ? Do you think it can be further improved ? Feel free to share your comments below.

About Vykthur

Mobile and Web App Developer and Researcher. Passionate about learning, teaching, and recently - writing.
This entry was posted in Android Tutorials, Cocos2d, Cocos2D for android, Programming and tagged , , , , , . Bookmark the permalink.
  • Vlad

    Wonderful tutorial as always. Looking forward to the next ones. Anyhow thanks for the quick replies in the earlier posts. I will let you know how my app is coming along. One question though. How are the anchor points distributed on a portrait orientation? Also how can I have the orientation assigned automatically using the device’s accelerometer?

    • Vykthur

      Regarding automatically switching orientation, this can be set in the android manifest.xml file.
      You may consult the android documentation about that here ..

      http://developer.android.com/guide/topics/manifest/activity-element.html

      You will notice that most games have a fixed orientation and do not support automatic accelerometer based orientation switch. This is because you have to re-draw/re-align your content on layers each time the orientation changes. Most games also work best in a given orientation as it helps designers maximize the device screen real estate.

      Regards,
      -V

  • Vlad

    Hey man. I am trying to wrap my head around the camera intent and how should I implement it. I am guessing simply to make a method that brings up the camera and create a picture button with a callback to that. Is there any other way you suggest?

  • Jerry Hernandez

    Hi man! Im having problem with the scaling factor. whenever I load the application on my Galaxy S4, each of the picture tiles became so big that i only can see one tiles on the screen, the rest were being covered by one another. I tried the full code from Github, it has the same problem too! Any solutions??

    • Vykthur

      Hi Hernandez,

      Thanks alot for pointing that out! YOu are definitely right, the issue comes from the scale factors.
      There were places I simply uses float value multiplications to set scale
      e.g … x.setScale(1.5f) or I didnt set scale at all. Or I divided a value a float without scale … e.g x.height / 2.0f

      This is what causes the issues. Sorry about that. I was testing on a galaxy s2 , and It looked good there. I have access to an s4 right now and I have seen the issues you mention. The images on the pic puzzle bigggiees 🙂 . This is becaue of a division that was done without a scalefactor .. This line should be corrected to add scalefactor …

      scalefactor = TILE_SQUARE_SIZE / (150.0f*generalscalefactor) ;

      topleft = (int) ((TILE_SQUARE_SIZE / 2*generalscalefactor) + 15*generalscalefactor) ;

      Also, some of the labels are in need of similar adjustment. I have updated the git repo.

      Many thanks.

      • Jerry Hernandez

        Hi!

        Much appreciated with your solution there. I wasn’t able to scale it correctly because I left out “f” behind “1.2”. Now, I am having problems with 4×4 picture scale instead of 3×3.

  • Jayson Pinzon

    again I have problem with this 🙁 or Vykthur can you share to me the complete code for generateTile() ?

    • Vykthur

      Maybe you can download the entire code sample from github …
      https://github.com/chuvidi2003/PuzzleGame/archive/master.zip

  • Jayson Pinzon

    # Vykthur I can’t load the custom image in tile. how to do this ?

    • Vykthur

      What error are you encountering ? How did you try to load the image ? have you added the image to your asset folder ?

      -V

      • Jayson Pinzon

        yes I copied the image in the asset folder but when I run it it shows the previous runnable tile which is the number tile . I also follow the code above .. thanks for the help

      • Jayson Pinzon

        CCSprite tile = CCSprite.sprite(“tile.png”);

        I tried also to change the tile.png to different images but it doesn’t work at all it such a kind of images bounded together with different positions

  • jasmine teo

    Hi, can you do a tutorial on doing a scoring systems on cocos2d Android?

    • Vykthur

      Yeah. Thanks for the suggestion Jasmine. I’ll try to do that soon.
      Basically, what you will need to do is to use the built in android sqlite service

      A great tutorials that you can adapt to your game is here …

      http://developer.android.com/training/basics/data-storage/databases.html

      -V.

  • Jerry Hernandez

    Hi Vykthur, I was wondering if it is possible that the soft keyboard of android can be implemented ? If yes, how am I supposed to do that?

    • Vykthur

      Hi Jerry ,

      I think your best bet would be to display an android text box (which you could style to fit your game theme) . It is possible to show android UI elements in your game … just that you will have to call them from mainActivity.java .

      I try to provide some samples as soon as I have some time.

      -V

      • Jerry Hernandez

        Hi Vykthur,

        Just as I thought too, but I wasn’t able to run scene with the Button OnClick(Android UI Elements, XML Layout). Just like a playstation4 UI, enabling you to log in, and play the game using your name. Thank You for your response, hoping to see your new tutorial.