Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Warp Shift game, Game development, HTML5, Javascript and Phaser.

Recently I started playing again Warp Shift by Deep Silver FISHLABS on my iPhone and between a level and another I thought it could be fun to create something similar in HTML5 using Phaser framework. Warp Shift is a unique puzzle game set in a mysterious world. AppSpy says that it “is well-balanced and gorgeous to look at and filled to the brim with innovative twists and new ideas.” It’s not easy to create a detailed tutorial of a game like this one, so we are approaching it step by step. In the first step, this one, we are going to build the engine which will render the first three levels. There’s a precise reason behind this choice: they are the most basic levels, as starting from level 4 new elements are added, and as said we are going step by step. Let me show you the tilesheet used in the prototype:
We have, from left to right, top to bottom: the closed block, the block opened on the top, the block opened on the right, the block opened on the bottom, the block opened to the left, the player and the exit. This is how original levels are rendered: And this is the script capable of doing it:
// the game itself
var game;

// this object contains all customizable game options
// changing them will affect gameplay
var gameOptions = {

    // game width, in pixels
	gameWidth: 400,

    // game height, in pixels
	gameHeight: 400,

     // tile size, in pixels
    tileSize: 100,

    // margin between two tiles, in pixels
    tileMargin: 10
}

// some constants (actually they are variables) where to store tile properties
var UP = 1;
var RIGHT = 2;
var DOWN = 3;
var LEFT = 4;
var EXIT = 5;
var PLAYER = 6;

// function to create a block object
function block(){

    // this is the default block object
    var defaultBlock = {

        // can't walk through top side
        up: false,

        // can't walk through right side
        right: false,

        // can't walk through bottom side
        down: false,

        // can't walk through left side
        left: false,

        // there's no level exit on this block
        exit: false,

        // the player is not on this block
        player: false
    }

    // looping through all function arguments, if any
    for(var i = 0; i < arguments.length; i++){

        // checking the i-th argument
        switch(arguments[i]){

            // if it's UP, then set defaultBlock's "up" key to true
            case UP:
                defaultBlock.up = true;
                break;

            // if it's RIGHT, then set defaultBlock's "right" key to true
            case RIGHT:
                defaultBlock.right = true;
                break;

            // if it's DOWN, then set defaultBlock's "down" key to true
            case DOWN:
                defaultBlock.down = true;
                break;

            // if it's LEFT, then set defaultBlock's "left" key to true
            case LEFT:
                defaultBlock.left = true;
                break;

            // if it's EXIT, then set defaultBlock's "exit" key to true
            case EXIT:
                defaultBlock.exit = true;
                break;

            // if it's PLAYER, then set defaultBlock's "player" key to true
            case PLAYER:
                defaultBlock.player = true;
                break;
        }
    }
    return defaultBlock;
}

var levels = [

    // level 1
    [
        [block(), block(LEFT, EXIT)],
        [block(RIGHT, PLAYER), block()]
    ],

    // level 2
    [
        [block(), block(RIGHT, EXIT)],
        [block(LEFT, PLAYER), block()]
    ],

    // level 3
    [
        [block(), block(UP, PLAYER)],
        [block(DOWN, EXIT), block()]
    ]
]

// function to be execute once the page loads
window.onload = function() {

    // creation of a new Phaser Game
	game = new Phaser.Game(gameOptions.gameWidth, gameOptions.gameHeight);

    // adding "TheGame" state
    game.state.add("TheGame", TheGame);

    // launching "TheGame" state
    game.state.start("TheGame");
}

/* ****************** TheGame state ****************** */

var TheGame = function(){};

TheGame.prototype = {

    // function to be executed when the game preloads
    preload: function(){

        // load the spritesheet with all tiles
        game.load.spritesheet("tile", "assets/sprites/tile.png", gameOptions.tileSize, gameOptions.tileSize);

        // scaling the game to cover the entire screen, while keeping its ratio
        game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

        // horizontally centering the game
		game.scale.pageAlignHorizontally = true;

        // vertically centering the game
		game.scale.pageAlignVertically = true;

        // set background color
        game.stage.backgroundColor = 0x111111;
    },

    // function to be executed as soon as the game has completely loaded
  	create: function(){

        // we start from level 0
        this.level = 0;

        // this method generates a level
        this.generateLevel();
  	},

    // function to generate a level
    generateLevel: function(){

        // tileAndMargin is the sum of tile and margin size
        var tileAndMargin = gameOptions.tileSize + gameOptions.tileMargin;

        // creation of a group where to place level items
        this.levelGroup = game.add.group();

        // temporary array to store the level so we don't need to modify the original levels
        this.tempLevel = [];

        // looping through level rows
        for(var i = 0; i < levels[this.level].length; i++){

            // preparing the temporary array to store the i-th row
            this.tempLevel[i] = [];

            // looping through level columns
            for(var j = 0; j < levels[this.level][i].length; j++){

                // adding the tile on the stage
                var tile = game.add.image(j * tileAndMargin + gameOptions.tileSize / 2, i * tileAndMargin + gameOptions.tileSize / 2, "tile");

                // set tile registration point to its center
                tile.anchor.set(0.5);

                // adding tile to level group
                this.levelGroup.add(tile);

                // now it's time to assign the tile a frame. If there is no exit, it's frame zero
                if(!levels[this.level][i][j].up && !levels[this.level][i][j].right && !levels[this.level][i][j].down && !levels[this.level][i][j].left){
                    tile.frame = 0;
                }
                else{

                    // if there's an exit on the top, it's frame one
                    if(levels[this.level][i][j].up){
                        tile.frame = 1
                    }

                    // if there's an exit on the right, it's frame two
                    if(levels[this.level][i][j].right){
                        tile.frame = 2;
                    }

                    // if there's an exit on the bottom, it's frame three
                    if(levels[this.level][i][j].down){
                        tile.frame = 3;
                    }

                    // if there's an exit on the left, it's frame four
                    if(levels[this.level][i][j].left){
                        tile.frame = 4;
                    }

                    // if there's the level exit...
                    if(levels[this.level][i][j].exit){

                        // we add the exit tile
                        var exit = game.add.image(0, 0, "tile");

                        // set exit tile registration point to its center
                        exit.anchor.set(0.5);

                        // assign exit tile frame six
                        exit.frame = 6;

                        // set exit tile as a child of current tile
                        tile.addChild(exit);
                    }

                    // if there's the player...
                    if(levels[this.level][i][j].player){

                        // we add the player tile
                        var player = game.add.image(0, 0, "tile");

                        // set player tile registration point to its center
                        player.anchor.set(0.5);

                        // assign player tile frame five
                        player.frame = 5;

                        // set player tile as a child of current tile
                        tile.addChild(player)
                    }
                }

                // now copying original level item into temporary level item
                this.tempLevel[i][j] = {
                    up:  levels[this.level][i][j].up,
                    right: levels[this.level][i][j].right,
                    down: levels[this.level][i][j].down,
                    left: levels[this.level][i][j].left,
                    exit: levels[this.level][i][j].exit,
                    player: levels[this.level][i][j].player,

                    // here we store the tile
                    sprite: tile
                }
            }
        }

        // center the group on the stage
        this.levelGroup.x = (game.width - this.levelGroup.width) / 2;
        this.levelGroup.y = (game.height - this.levelGroup.width) /2;
    }
}
Download the source code and familiarize with it because next time I will show you how to add more complex levels and above all how to add interactivity to the game.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.