Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Magick game, Game development, HTML5, Javascript and Phaser.

Some time ago I downloaded an iPad game called Magick.

It’s a retro platformer where a mage called Oz walks and jumps by himself, and you can summon a crate, but only one, to modify the terrain.

The way you control the player, which actually you don’t control, you can just make some changes to the level, is really interesting to build with Phaser.

Since the game is easier to play than to describe, have a look at what you are going to build:

The player walks and climbs on his own, you can only click anywhere on an empty spot to summon a crate, but you can submit only one crate at once. Will you be able to reach the upper platform on the left?

Before I show you the fully commented source code, please note the level has been built with Tiled and exported as JSON. I am telling you this because some of the names used in the game itself are taken from the JSON data in level map.

Here is the Tiled output:

{ "height":10,
 "layers":[
        {
         "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
         "height":10,
         "name":"myLevel",
         "opacity":1,
         "type":"tilelayer",
         "visible":true,
         "width":25,
         "x":0,
         "y":0
        }],
 "orientation":"orthogonal",
 "properties":
    {

    },
 "tileheight":32,
 "tilesets":[
        {
         "firstgid":1,
         "image":"rock.png",
         "imageheight":32,
         "imagewidth":32,
         "margin":0,
         "name":"rock",
         "properties":
            {

            },
         "spacing":0,
         "tileheight":32,
         "tilewidth":32
        }, 
        {
         "firstgid":2,
         "image":"block.png",
         "imageheight":32,
         "imagewidth":32,
         "margin":0,
         "name":"block",
         "properties":
            {

            },
         "spacing":0,
         "tileheight":32,
         "tilewidth":32
        }],
 "tilewidth":32,
 "version":1,
 "width":25
}

And here is the fully commented source code, just a bunch of lines:

window.onload = function() {	
     
     // the game itself
	var game = new Phaser.Game(800, 320);
	// the player! The hero of the game!!
     var player;
     // level map, created with Tiled
	var map;
     // map layer with level data
	var levelLayer;
     // player horizontal speed
	var playerSpeed = 120;
     // map tile size, in pixels
	var tileSize = 32;
     // tilePoint will be used to save the coordinates of the tile placed by the player
	var tilePoint = null;
     // is the player jumping?
	var playerJumping = false;
     
     // playGame function, to be bound to "PlayGame" state
	var playGame = function(game){}
	
     playGame.prototype = {
          // preloading assets
		preload: function(){
               // map data
			game.load.tilemap("map", "map.json", null, Phaser.Tilemap.TILED_JSON);
			// rock image, used to draw walls
               game.load.image("rock", "rock.png");
               // block image, used to let the player add tiles to the map
			game.load.image("block", "block.png");
               // the player
			game.load.image("player", "player.png");
		},
          // once the game has been created
		create: function(){
               // starting arcade physics
			game.physics.startSystem(Phaser.Physics.ARCADE);
               // adding the map
			map = game.add.tilemap("map");
               // adding "rock" and "block" graphic assets to the map
			map.addTilesetImage("rock");
			map.addTilesetImage("block");
               // both "rock" and "block" are solid
			map.setCollisionBetween(1,2);
               // we are going to use "myLevel" layer, as created with Tiled
			levelLayer = map.createLayer("myLevel");
               // adding the player
			player = game.add.sprite(48,226,"player");
			// setting player registration point in the center
               player.anchor.setTo(0.5);
               // enabling arcade pysics to the player
			game.physics.enable(player, Phaser.Physics.ARCADE);
               // setting player gravity
			player.body.gravity.y = 400;
               // waiting for input, both touch or mouse click, to call addBlock function
			game.input.onDown.add(addBlock, this);		
		},
          // function to be executed at each frame
		update:function(){
               // setting player x speed to zero
			player.body.velocity.x = 0;
               // check for collision between the player and the level, and call "movePlayer" if there's a collision
			game.physics.arcade.collide(player, levelLayer, movePlayer);
		}
	}
	
	function movePlayer(){
          // is the player blocked down, that is: is the player on the floor?
		if(player.body.blocked.down){
               // set player horizontal velocity
			player.body.velocity.x = playerSpeed;
               // the player is definitively not jumping
			playerJumping = false;
		}
          // is player speed greater than zero and the player is blocked right, that is the player is against a wall on the right?
		if(player.body.blocked.right && playerSpeed>0){
               // is the tile on player upper right diagonal empty, as well as the tile immediately above the player, or is the player already jumping?
			if((!map.getTileWorldXY(player.x+tileSize,player.y-tileSize,tileSize,tileSize,levelLayer)&&!map.getTileWorldXY(player.x,player.y-tileSize,tileSize,tileSize,levelLayer)) || playerJumping){
                    // jump
				jump();
			}
			else{
                    // invert player speed
				playerSpeed*=-1;
			}
		}
          // the same concept is applied to collisions on the left side of the player
		if(player.body.blocked.left && playerSpeed<0){
			if((!map.getTileWorldXY(player.x-tileSize,player.y-tileSize,tileSize,tileSize,levelLayer)&&!map.getTileWorldXY(player.x,player.y-tileSize,tileSize,tileSize,levelLayer)) || playerJumping){
				jump();
			}
			else{
				playerSpeed*=-1;
			}
		}	
	}
	
	function addBlock(e){
          // is the tile where we clicked/touched a null tile?
		if(!map.getTileWorldXY(e.x,e.y,tileSize,tileSize,levelLayer)){
               // is there already a tile placed by the player?
			if(tilePoint){
                    // remove the tile placed by the player
				map.removeTileWorldXY(tilePoint.x, tilePoint.y, tileSize, tileSize, levelLayer);	
			}
               // place the tile on mouse/touch position
			map.putTileWorldXY(2, e.x, e.y, tileSize, tileSize, levelLayer);
               // save placed tile position
			tilePoint = new Phaser.Point(e.x,e.y); 		
		}
	}
	
	function jump(){
          // setting player vertical velocity
		player.body.velocity.y = -100;
          // setting player horizontal velocity
		player.body.velocity.x = playerSpeed/4;
          // now the player is jumping	
		playerJumping = true;
	}
	
     // defining "PlayGame" state
	game.state.add("PlayGame",playGame);
     // run "PlayGame" state
	game.state.start("PlayGame")
}

I always say the funniest game are built on the simplest concepts, and here’s another one.

Download the source code and suggest some features to add 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.