Tutorials

Jscrambler Themed Sliding Puzzle Tutorial Built with Phaser.js

January 30th, 2017 | By Jscrambler | 6 min read

Every day, we encounter puzzles in various forms. Most of the JavaScript code is ultimately a technical puzzle waiting to be solved.

Developers must find creative solutions for these puzzles, from probing for weaknesses in real-world systems to creating scalable web apps.

Countless JavaScript frameworks are created with the express intent of solving a specific puzzle. One such framework is Phaser.js. If you’re a developer with a penchant for game development, you may have heard of it.

Game Development

Phaser is a well-designed and thoroughly documented JavaScript game development library created by the good folks at Photonstorm.

Building games is totally different than typical application development. It can be an especially daunting task for those new to game development. Fortunately, Phaser was built with the sole purpose of making game development easier.

Those lucky enough to have used a vintage Macintosh may have played the memorable sliding puzzle game that came included as part of Mac OS 7-9.

Because we now live in the Golden Age, we’ll create our own Jscrambler-themed sliding-puzzle game using Phaser.js. The basic game logic for our sliding puzzle game will be as follows:

  • Separating and shuffling the image into tiles

  • Event-handling of mouse-clicks

  • Moving tiles with animation

  • Re-calculating the tiles based on the position of the black tile

  • Define win conditions (puzzle-solved criteria) based on the position of indexed tiles


To begin, we encapsulate and load our entire game states using the Phaser.Game method. The game method falls within the scope of a single object, Phaser.Game. Put simply, the phaser game object represents the entire game state window:

Create a game.js

    create: create
});

var PIECE_WIDTH = 200,
    PIECE_HEIGHT = 200,
    BOARD_COLS, BOARD_ROWS;


Our first few variables define the size of each piece of the puzzle so that the background image is sliced correctly:

var piecesGroup,
    piecesAmount,
    shuffledIndexArray = [];


We then create variables for our group of pieces, amount of pieces, and the Array for our shuffled puzzle, shuffledIndexArray.

function preload() {
    game.load.spritesheet("background", "15puzzlebg.png", PIECE_WIDTH, PIECE_HEIGHT);
}


Next, we preload our background image, while we define the parameters for the width and height of each sliding piece.

function create() {
    prepareBoard();
}


Here is where all the fun begins, by creating a function that prepares our board with the individual pieces shuffled we can give each tile a variable to track index positions down the line.

function prepareBoard() {

        var piecesIndex = 0,
            i, j,
            piece;


The first portion of the function has to set the Index to 0 while defining our variables for the board rows and columns.

    BOARD_COLS = Math.floor(game.world.width / PIECE_WIDTH);
    BOARD_ROWS = Math.floor(game.world.height / PIECE_HEIGHT);


In this next portion of our code, we pass in the width and height we selected earlier and set the state of the board. We create a variable for the shuffled Index as shuffledIndexArray.

    piecesAmount = BOARD_COLS * BOARD_ROWS;
    shuffledIndexArray = createShuffledIndexArray();


The piecesGroup variable houses our algorithm. The purpose of our algorithm is to check for a black space within the group of shuffled pieces while placing the tile piece positions and allowing for user input:

    piecesGroup = game.add.group();


    for (i = 0; i < BOARD_ROWS; i++) {
        for (j = 0; j < BOARD_COLS; j++) {
            if (shuffledIndexArray[piecesIndex]) {
                piece = piecesGroup.create(j * PIECE_WIDTH, i * PIECE_HEIGHT, "background", shuffledIndexArray[piecesIndex]);
            } else { //initial position of black piece

                piece = piecesGroup.create(j * PIECE_WIDTH, i * PIECE_HEIGHT);
                piece.black = true;
            }
            piece.name = 'piece' + i.toString() + 'x' + j.toString();
            piece.currentIndex = piecesIndex;
            piece.destIndex = shuffledIndexArray[piecesIndex];
            piece.inputEnabled = true;
            piece.events.onInputDown.add(selectPiece, this);
            piece.posX = j;
            piece.posY = i;
            piecesIndex++;
        }
    }

    }

    function selectPiece(piece) {


        var blackPiece = canMove(piece);



        if (blackPiece) {
            movePiece(piece, blackPiece);
        }

    }


We use the above code to check for our black tile nearby. The canMove function is for ensuring that the tile piece that is interacted with is allowed to move to a new position.

function canMove(piece) {

    var foundBlackElem = false;

    piecesGroup.children.forEach(function(element) {
        if (element.posX === (piece.posX - 1) && element.posY === piece.posY && element.black ||
            element.posX === (piece.posX + 1) && element.posY === piece.posY && element.black ||
            element.posY === (piece.posY - 1) && element.posX === piece.posX && element.black ||
            element.posY === (piece.posY + 1) && element.posX === piece.posX && element.black) {
            foundBlackElem = element;
            return;
        }
    });

    return foundBlackElem;
}


Next, we add the movePiece function to create a temporary piece variable that is based on the current index of the piece.

function movePiece(piece, blackPiece) {


        var tmpPiece = {
            posX: piece.posX,
            posY: piece.posY,
            currentIndex: piece.currentIndex
        };


Our code should switch the places of the chosen piece with our black tile aka blackPiece. Then after every move we initiate a check to see if the puzzle is completed with checkIfFinished();

    game.add.tween(piece).to({
        x: blackPiece.posX * PIECE_WIDTH,
        y: blackPiece.posY * PIECE_HEIGHT
    }, 300, Phaser.Easing.Linear.None, true);

    piece.posX = blackPiece.posX;
    piece.posY = blackPiece.posY;
    piece.currentIndex = blackPiece.currentIndex;
    piece.name = 'piece' + piece.posX.toString() + 'x' + piece.posY.toString();

    // previously clicked piece is the new black tile
    blackPiece.posX = tmpPiece.posX;
    blackPiece.posY = tmpPiece.posY;
    blackPiece.currentIndex = tmpPiece.currentIndex;
    blackPiece.name = 'piece' + blackPiece.posX.toString() + 'x' + blackPiece.posY.toString();
    checkIfFinished();
    }

    function checkIfFinished() {

        var isFinished = true;

        piecesGroup.children.forEach(function(element) {
            if (element.currentIndex !== element.destIndex) {
                isFinished = false;
                return;
            }
        });

        if (isFinished) {
            showFinishedText();
        }
    }


Lastly, we have to announce when the user completes the puzzle correctly by creating a showFinished Text function:

function showFinishedText() {
    var style = {
        font: "40px Arial",
        fill: "#000",
        align: "center"
    };
    var text = game.add.text(game.world.centerX, game.world.centerY, "Congratulations! \nYou made it!", style);
    text.anchor.set(0.5);
}


The createShuffledIndexArray creates a brand new array based on the shuffled puzzle piece index.

function createShuffledIndexArray() {

    var indexArray = [];

    for (var i = 0; i < piecesAmount; i++) {
        indexArray.push(i);
    }

    return shuffle(indexArray);

}


The following is likely the second most important function within our game. Within this function, we use Math.floor to create a randomized index which we iterate over every time we check to see if our puzzle is shuffled.

function shuffle(array) {

    var counter = array.length,
        temp,
        index;

    while (counter > 0) {
        index = Math.floor(Math.random() * counter);

        counter--;

        temp = array[counter];
        array[counter] = array[index];
        array[index] = temp;
    }

    return array;
}


Our completed Jscrambler sliding puzzle code is somewhat lengthy but we’ve created an entire game using only one library.

Adding Jscrambler Security

The final piece of the puzzle is protecting our app.

The next part is as easy as copying the code directly as new files within the dashboard:

jscrambler-dashboardAs a priority, we’ll need to download a JSON file with the corresponding API Credentials. These can also be found on the Profile Page once you’ve logged into the Jscrambler Account Panel.

Here we're applying transformations that include Self Defending and Date Locks. Self Defending will protect the App from being tampered with and debugged, while the Date Lock will only allow the App to run in a certain time interval, useful for delivering expirable demos.

In addition, Date Locks, and all other Locks, allow you to have a warning function that will be triggered if someone tries to run the App outside the parameters you set.

With this function, you can be warned whenever someone tries to use your App incorrectly.

jscrambler.json
{
  "keys": {
    "accessKey": “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”,
    "secretKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  },
  "applicationId": “YYYYYYYYYYYYYYYYYY”,
  "params": [{
        "name": "whitespaceRemoval"
    }, {
        "options": {
            "mode": "SAFEST"
        },
        "name": "identifiersRenaming"
    }, {
        "name": "duplicateLiteralsRemoval"
    }, {
        "name": "functionReordering"
    }, {
        "name": "dotToBracketNotation"
    }, {
        "name": "functionOutlining"
    }, {
        "name": "selfDefending"
    }, {
        "name": "booleanToAnything"
    }, {
        "name": "propertyKeysReordering"
    }, {
        "name": "propertyKeysObfuscation"
    }, {
      "name": "dateLock",
      "options": {
        "endDate": "2017/02/01",
        "startDate": "2017/01/18"
      }
    }],
  "areSubscribersOrdered": false,
  "applicationTypes": {
    "webBrowserApp": true,
    "desktopApp": false,
    "serverApp": false,
    "hybridMobileApp": false,
    "javascriptNativeApp": false,
    "html5GameApp": true
  },
  "languageSpecifications": {
    "es5": true,
    "es6": false,
    "es7": false
  }
}


That’s it! Simply running Webpack after the configuration of our webpack.config.js will bundle our entire Puzzle.

Conclusion

Anyone willing to dip their feet in the waters of game development should know Phaser.js is shallow enough to keep you from drowning in complexity.

There are a few other options out there for game development with JavaScript. Pixi.js (which Phaser wisely incorporates) is great for lightning-fast 2D rendering and Bablyon.js is used for 3D/WebGL games.

Where Phaser stands out is that it provides support for both Canvas and WebGL rendering. It garners wide support and has a very active community, making it one of the best-performing JS game engines available today.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Cybersecurity

Can ChatGPT reverse engineer Jscrambler obfuscation?

As the potential of ChatGPT (and of Generative AI in general) is unveiled, experts and developers keep asking questions and experimenting with the tool. Can it crack even the strongest protections...

June 13, 2023 | By Jscrambler | 6 min read

Jscrambler

5 Steps to Fine-tune your Jscrambler Application

Here are some features and strategies you can use to make your application as protected as possible without compromising its original performance.

June 21, 2017 | By Carlos Matias | 5 min read

Section Divider

Subscribe to Our Newsletter