Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Puzzle game for tablets and SmartPhones

4.90/5 (34 votes)
26 Feb 2013BSD5 min read 64.5K   5.1K  
This article shows how to create Puzzle game using Moscrif SDK.

Image 1

Contents

Introduction

Puzzle is a simple game suitable for all ages. The goal of the game is to put the right pieces into correct shapes. Everyone has had a chance to play a puzzle game in real life but there are not that many puzzle games for mobiles. Nevertheless, this game is suitable as a stand-alone game for children but it can be also used as a great marketing tool.

In this article, we would like to show you how to create this game for multiple mobile platforms using only one code.

Background

To overcome platform differences, we will use Moscrif SDK (available free for Open Source projects). This SDK comes with object-oriented JavaScript and an open-source framework which is easy to learn. The SDK also contains publishing tools that generate native installation files.

About the game

Our game is made for Tablets and other devices which run iOS and Android, with a screen resolution larger than 600x900px. I have tested it on Amazon Kindle Fire, Galaxy Tab, Nook Color, iPad 2, and iPhone 4.

In this case, we designed a crocodile to be the puzzle objective so every piece has to be put in the correct shape in order for the picture of the crocodile to appear. This puzzle game can be implemented in many ways. For marketing purposes, you can use your company logo, product photo, etc.

User interface 

When making an app, our goal is  to make a simple user interface, which gives the user the best experience possible.

Image 1: User interface

Image 2

User experience  

Recently, the mobile industry has been putting a lot of emphasis on user experience because programmers are finding out that only applications with a user-friendly interface can succeed. It means that applications have to do what the user’s intuition expects to do, while being responsive and smooth. To achieve this experience, parts can be moved smoothly according to finger movement and when a particular part is close to the position where it belongs, the part automatically snaps to it. 

Development process

Using Moscrif SDK saves a lot of time, because we do not need to create three separate code for every platform. We will create only one code and publish it for all target platforms.

There are three tasks that need to be addressed in order to create this game. The first one is the part distribution algorithm which needs to take place right at the beginning of the game. During the game, there are two other tasks that need to be accomplished to make this a good puzzle game: part dragging and snapping.

Parts distribution

Restart function

When the user taps onto the screen or every time the user hits the Refresh button, all puzzle parts are placed randomly on the playing field. The position for every part is found separately.

Code Example 1:  Restart function - calls _findPosition for every puzzle part

C++
/**
Function sets objects to the init state.
*/
function restart()
{
    // go throw all objects in this._parts array
    for (var part in this._parts) {
        part.isOnPlace = false;
        // find new position for this part
        this._findPosition(part);
    }
    this._onPlace = 0;
    this._pulseButtons();
}

Function _findPosition

Function _findPosition is even more interesting because it runs in a cycle until the right position for that particular part is found. Every run of this cycle generates a new random position and then checks if it doesn’t overlays another, already placed, part. However, in some cases, a cycle as we described can run forever. To prevent this critical mistake, we added a counter property and a max number of cycle repetitions.

Image 2: flow chart - _findPosition

Image 3

Example code 2: Function _findPosition finds a suitable position for the puzzle part

C++
/**
Part is set on new position.
@param part Part
*/
function _findPosition(part)
{
    //Helper function
    function random(from, to) { return from + rand(to-from+1); }
 
    // number of while runnings.
    var counter = 0;
    while (counter < 100/*Max repeats*/ ) {
        counter ++;
        //Set random position on axis y.
        part.y = random(part.height/2,System.height-part.height/2);
        //If y coordinate is over crocodile
        if (part.y+part.height/2 < this._finalTop)
            part.x = random(part.width/2, System.width - part.width/2);
        else {
            //Choose one from two areas (left or right from crocodile).
            var area = rand(2);
            if (area == 0)
                part.x = random(part.width/2, this._finalLeft-part.width/2);
            else
                part.x = random(this._finalLeft + this._final.width,
                                        System.width-part.width/2);
        }
        //Check if parts overlay.
        var collision = false;
        for (var p in this._parts) {
            if (part.intersectsBounds(p)) {
                collision = true;
                break;
            }
        }
        //If they do not overlay, it jumps from while loop.
        if (!collision)
            break;
    }
}

Parts dragging 

Smooth part dragging is important to provide an enjoyable user experience. When the user taps on a puzzle part, finger movement will change the position of the part.  

Example code 3: Function _getPart - finds the puzzle part under the tap position.

C++
/**
Return part by coordinates.
@param x Integer Position on x axis.
@param y Integer Position on y axis.
@return Part
*/
function _getPart(x, y)
{
    //Auxiliary variable remembers picture located on position x y.
    //init state is nothing
    var searchPart = #nothing;
 
    //search image located on position x y
    for (var part in this._parts) {
        if (part.intersectsPoint(x, y))
            searchPart = part;
    }
 
    //If image is found on that position.
    if (searchPart != #nothing) {
        //set relative position
        searchPart.relX = searchPart.x - x;
        searchPart.relY = searchPart.y - y;
 
        //Move up
        this._moveUp(searchPart);
    }
 
    return searchPart;
}

Example code 4: Function pointerDragged - changes the part position in the pointer-dragged event

C++
/**
Event fired at pointer-dragged.
@param x Integer Position on x axis
@param y Integer Position on y axis
*/
function pointerDragged(x, y)
{
    super.pointerDragged(x, y);
    if (this._catchImage != #nothing) {
        this._catchImage.x = x;
        this._catchImage.y = y;
        this._catchImage.push(this);
    }
}

Parts snapping  

Snapping is another feature that provides a good user experience. While the user is dragging a part, the application calculates its distance from the position where it belongs. If the distance is less than System.width / 38, it automatically snaps to its place.

Example code 5: Function push - calculates the distance from the position where it belongs

C++
/**
Check distance from location where part should be. If it is too close move it to the right place.
@param sender Object
*/
function push(sender)
{
    //Calculate the distance from the position
    //where the image should be placed
    // |draw, loc|
    var sizeX = Math.pow((this.locX + this.width/2) - this.x,2);
    var sizeY = Math.pow((this.locY + this.height/2) - this.y,2);
    var size  = Math.sqrt(sizeX + sizeY);
 
    //If the distance is smaller than constant
    if (size < System.width / 38) {
        //Set picture location on the right position.
        this.x = this.locX + this.width/2 - this.relX;
        this.y = this.locY + this.height/2 - this.relY;
        //If picture wasnt on the right position.
        if (!this.isOnPlace) {
            //Increment variable, which remember count of picture, which are on right position.
            sender._onPlace++;
            this.isOnPlace = true;
        }
    //Picture was on right position, but he is not anymore.
    } else if (this.isOnPlace) {
        sender._onPlace--;
        this.isOnPlace = false;
    }
}
Image 3: Snapping area

Image 4

As you can see in the previous example, if a part is snapped on its position, the _onPlace variable is increased. The _victory method checks if all parts are snapped on their position (_onPlace == number of parts). If the _victory method returns true, the bitmap of the final image is drawn.

Summary  

Now you know how to create your own puzzle game and what features are required to make the game enjoyable while providing a more user-friendly experience. Yes, yes, we know the game is very basic but it was made for learning purposes and it should serve as a base ground for your next awesome app. As we mentioned before, implementing such a game into your already existing business app will increase brand awareness and customer engagement. And in addition to all of this amazing stuff, let’s not forget that this game was made in object-oriented JavaScript, can be run on three platforms (iOS, Android, and Bada), as well as on Tablets and SmartPhones. Happy coding!

More resources

More samples, demos, and information about Moscrif can be found on its homepage: www.moscrif.com.

License

This article, along with any associated source code and files, is licensed under The BSD License