Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 773635 of 2D maze game with device orientation

  • Revision slug: Games/Workflows/HTML5_Gamedev_Phaser_Device_Orientation
  • Revision title: 2D maze game with device orientation
  • Revision id: 773635
  • Created:
  • Creator: chrisdavidmills
  • Is current revision? No
  • Comment

Revision Content

Introduction

In this tutorial we’ll go through the process of building an HTML5 mobile game that uses the Device Orientation API and Vibration API in the gameplay and is built using the Phaser framework. Basic JavaScript knowledge is required to learn from the article below, and at the end of the tutorial we will have a fully functional demo game Cyber Orb.

Phaser framework

Phaser is a framework for building desktop and mobile HTML5 games. It’s quite new, but grows rapidly thanks to the passionate community involved in the development process. You can check it out on GitHub where it’s open sourced, read the online documentation and go through the big collection of examples. The Phaser framework provide you with the set of tools that will speed up development and help handle generic tasks needed to complete the game, so you can focus on the game idea itself.

Starting with the project

You can see the code of the project on GitHub. The folder structure is quite straightforward: the starting point is the index.html file where we initialize the framework, set up the Canvas and play the game. You can click that file in your favourite browser to launch the game and try it. There are also three folders: img, src and audio - the first one contains all the images that we will use in the game, the second one have the JavaScript files with all the source code of the game defined inside, and in the third folder you can find the sound files used in the game.

Setting up the Canvas

We will be rendering our game on Canvas, but we won't do it manually - it will be taken care of by the framework. Let’s set it up: our starting point is the index.html file with the following content:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Cyber Orb demo</title>
    <style> body { margin: 0; background: #333; } </style>
    <script src="src/phaser-arcade-physics.2.2.2.min.js"></script>
    <script src="src/Boot.js"></script>
    <script src="src/Preloader.js"></script>
    <script src="src/MainMenu.js"></script>
    <script src="src/Howto.js"></script>
    <script src="src/Game.js"></script>
</head>
<body>
<script>
(function() {
    var game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game');
    game.state.add('Boot', Ball.Boot);
    game.state.add('Preloader', Ball.Preloader);
    game.state.add('MainMenu', Ball.MainMenu);
    game.state.add('Howto', Ball.Howto);
    game.state.add('Game', Ball.Game);
    game.state.start('Boot');
})();
</script>
</body>
</html>

It looks like a simple HTML website with some basic content in the <head> section: charset, title, CSS styling and the inclusion of the JavaScript files. The <body> contains initialization of the Phaser framework and the definitions of the game states. You can check the Building Monster Wants Candy article for the in-depth introduction to the basic Phaser-specific functions and methods.

Managing game states

The states in Phaser are a separate parts of the game logic, in our case we’re loading them from independent JavaScript files for better maintainability. The basic states used in this game are: Boot, Preloader, MainMenu, Howto and Game. Boot will take care of initializing a few settings, Preloader will load all of the assets like graphics and audio, MainMenu is the menu with the start button, Howto shows how to play instructions and the Game state lets you actually play the game. Let's quickly go though the content of those states.

Boot.js

The Boot state is the first one in the game.

var Ball = {
    _WIDTH: 320,
    _HEIGHT: 480
};
Ball.Boot = function(game) {};
Ball.Boot.prototype = {
    preload: function() {
        this.load.image('preloaderBg', 'img/loading-bg.png');
        this.load.image('preloaderBar', 'img/loading-bar.png');
    },
    create: function() {
        this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
        this.game.scale.pageAlignHorizontally = true;
        this.game.scale.pageAlignVertically = true;
        this.game.state.start('Preloader');
    }
};

The main Ball object is defined and we're adding two variables called _WIDTH and _HEIGHT that are the width and the height of the game Canvas - they will help us position elements on the screen. We're loading two images first that will be used later in the Preload state to show the progress of loading all the other assets. The create function holds some basic configuration: we're setting up the scaling and alignment of the Canvas, and moving on to the Preload state when everything's ready.

Preloader.js

The Preloader state takes care of loading all the assets:

Ball.Preloader = function(game) {};
Ball.Preloader.prototype = {
    preload: function() {
        this.preloadBg = this.add.sprite((Ball._WIDTH-297)*0.5, (Ball._HEIGHT-145)*0.5, 'preloaderBg');
        this.preloadBar = this.add.sprite((Ball._WIDTH-158)*0.5, (Ball._HEIGHT-50)*0.5, 'preloaderBar');
        this.load.setPreloadSprite(this.preloadBar);

        this.load.image('ball', 'img/ball.png');
        // ...
        this.load.spritesheet('button-start', 'img/button-start.png', 146, 51);
        // ...
        this.load.audio('audio-bounce', ['audio/bounce.ogg', 'audio/bounce.mp3', 'audio/bounce.m4a']);
    },
    create: function() {
        this.game.state.start('MainMenu');
    }
};

There are single images, spritesheets and audio files loaded by the framework. In this state the preloadBar is showing the progress on the screen. After all the assets are loaded, the MainMenu state is launched.

The MainMenu state shows the main menu of the game where you can start playing by clicking the button.

Ball.MainMenu = function(game) {};
Ball.MainMenu.prototype = {
    create: function() {
        this.add.sprite(0, 0, 'screen-mainmenu');
        this.gameTitle = this.add.sprite(Ball._WIDTH*0.5, 40, 'title');
        this.gameTitle.anchor.set(0.5,0);
        this.startButton = this.add.button(Ball._WIDTH*0.5, 200, 'button-start', this.startGame, this, 2, 0, 1);
        this.startButton.anchor.set(0.5,0);
        this.startButton.input.useHandCursor = true;
    },
    startGame: function() {
        this.game.state.start('Howto');
    }
};

Instead of jumping directly into the action, the game will show the screen with the information on how to play the game.

How to play

Ball.Howto = function(game) {
};
Ball.Howto.prototype = {
    create: function() {
        this.buttonContinue = this.add.button(0, 0, 'screen-howtoplay', this.startGame, this);
    },
    startGame: function() {
        this.game.state.start('Game');
    }
};

The Howto state is showing the gameplay instructions on the screen before starting the game. After clicking the screen the actual game is launched.

The Game

The Game state from the Game.js file is where all the magic happen. All the initialization is in the create() function (launched once at the beginning of the game), some things will require adding them to the update() function (executed at every frame), and we will also write our own functions to handle more complicated tasks.

Ball.Game = function(game) {};
Ball.Game.prototype = {
    create: function() {},
    initLevels: function() {},
    showLevel: function(level) {},
    updateCounter: function() {},
    managePause: function() {},
    manageAudio: function() {},
    update: function() {},
    wallCollision: function() {},
    handleOrientation: function(e) {},
    finishLevel: function() {}
};

The create and update functions are framework-specific, while others are our own creations: initLevels initializes the level data, showLevel prints the level data on the screen, updateCounter updates the time spent on playing the game, managePause pauses and resumes the game, manageAudio turns the sounds on and off, wallCollision is executed when the ball hits the walls or other objects, handleOrientation is the function bound to the event responsible for the Device Orientation API and finishLevel is loading a new level if there is any, or finishing the game.

Adding the ball and its motion mechanics

First, let’s go to the create function, initialize the ball object itself and assign a few properties to it:

this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, 'ball');
this.ball.anchor.set(0.5);
this.physics.enable(this.ball, Phaser.Physics.ARCADE);
this.ball.body.setSize(18, 18);
this.ball.body.bounce.set(0.3, 0.3);

We’re adding a sprite at the given place on the screen and using the 'ball' image from the loaded graphic assets. We’re also setting the anchor of any physic calculations to the middle of the ball, then enabling the ball for the Arcade physics engine, and setting the size of the body for the collision detection. The bounce property is used to set the bounciness of the ball when it hits the obstacles.

Controlling the ball

It’s cool to have the ball ready to be thrown around the play area, but it’s also important to be able to do it. Now we will add the ability to control the ball with the keyboard on the desktop devices, and then we will move to the implementation of the Device Orientation API. Let’s focus on the keyboard first:

this.keys = this.game.input.keyboard.createCursorKeys();

As you can see there’s a special Phaser function which will give us an object with the four arrow keys to play with: up, down, left and right. The this.keys object will then be checked against player input, so the ball can react accordingly with the prefedined force:

if(this.keys.left.isDown) {
    this.ball.body.velocity.x -= this.movementForce;
}
else if(this.keys.right.isDown) {
    this.ball.body.velocity.x += this.movementForce;
}
if(this.keys.up.isDown) {
    this.ball.body.velocity.y -= this.movementForce;
}
else if(this.keys.down.isDown) {
    this.ball.body.velocity.y += this.movementForce;
}

The code above is in the update function, so it will be fired on every frame. That way we can check which key is pressed at the given frame and apply the defined force to the ball, thus increase the velocity in the proper direction.

Implementing the Device Orientation API

The interesting part of the game is that it uses Device Orientation API on mobile devices. Thanks to this you can play the game by tilting the device in the direction you want the ball to roll. Here’s the code responsible for this:

window.addEventListener("deviceorientation", this.handleOrientation, true);

We’re adding an event listener to the "deviceorientation" event and binding the handleOrientation function which looks like this:

handleOrientation: function(e) {
    var x = e.gamma;
    var y = e.beta;
    Ball._player.body.velocity.x += x;
    Ball._player.body.velocity.y += y;
},

The more you tilt the device, the more force is applied to the ball and the velocity is higher.

Adding the hole

Our main purpose of the game is to move the ball from the starting position to the ending position which in our case will be a hole in the ground. Implementation looks very similar to the part where we created the ball:

this.hole = this.add.sprite(Ball._WIDTH*0.5, 90, 'hole');
this.physics.enable(this.hole, Phaser.Physics.ARCADE);
this.hole.anchor.set(0.5);
this.hole.body.setSize(2, 2);

The difference is that our hole’s body will not move when we hit it with the ball and will have the collision detection calculated (which will be discussed further in this article).

Building the block labyrinth

To make the game harder and more interesting we should build some obstacles on the way from the starting point to the end of the level, so let's build a labyrinth. We could use a level editor, but for the sake of this tutorial let's create something on our own.

We'll have a level data holding the information of the particular blocks - the top and left absolute positions in pixels and the type of the block - horizontal or vertical. Then, to load the level we need we will parse the data and show the blocks specific for that level. In the initLevels function we have:

this.levelData = [
    [
        { x: 96, y: 224, t: 'w' }
    ],
    [
        { x: 72, y: 320, t: 'w' },
        { x: 200, y: 320, t: 'h' },
        { x: 72, y: 150, t: 'w' }
    ],
    // ...
];

Every array element holds the collection of the blocks with the x, y position and t type. In the loop we're creating the items using the framework:

for(var i=0; i<this.maxLevels; i++) {
    var newLevel = this.add.group();
    newLevel.enableBody = true;
    newLevel.physicsBodyType = Phaser.Physics.ARCADE;
    for(var e=0; e<this.levelData[i].length; e++) {
        var item = this.levelData[i][e];
        newLevel.create(item.x, item.y, 'element-'+item.t);
    }
    newLevel.setAll('body.immovable', true);
    newLevel.visible = false;
    this.levels.push(newLevel);
}

Everything is stored in this.levels array, and is by default invisible. Then, to load specific level we just have to make sure the previous level is hidden and show the current one:

showLevel: function(level) {
    var lvl = level | this.level;
    if(this.levels[lvl-2]) {
        this.levels[lvl-2].visible = false;
    }
    this.levels[lvl-1].visible = true;
}

Thanks to that the game gives the player a challenge - now he have to roll the ball across the play area and guide it through the labyrinth built from the blocks. It's just an example of loading the levels, and there are only 5 of them just to showcase the idea, but you can work on expanding that on your own.

Collision detection

We have the ball that is controlled by the player, the hole to reach and the obstacles blocking the way. There’s a problem though – our game don’t have the collision detection yet, so nothing happens when the ball hits the blocks, it just goes through. That’s not the effect we wanted to achieve, so let’s work on it. The good news is that the framework will take care of calculating the collision detection, we only have to specify the colliding objects:

this.physics.arcade.collide(this.ball, this.borderGroup, this.wallCollision, null, this);
this.physics.arcade.collide(this.ball, this.levels[this.level-1], this.wallCollision, null, this);

This will tell the framework to execute the wallCollision function when the ball will hit any of the walls. We can use the wallCollision function to add any functionality we want like playing the bounce sound or implementing the Vibration API.

Adding the sound

Among the preloaded assets there was an audio file (in various formats for browser compatibility) which we can use now. It have to be defined in the create function first:

this.bounceSound = this.game.add.audio('audio-bounce');

Then, if the status of the audio is true (so the sounds in the game are enabled), we can play it in the wallCollision function:

if(this.audioStatus) {
    this.bounceSound.play();
}

That's all - loading and playing the sounds is easy with Phaser.

Implementing the Vibration API

When collision detection works as expected let's add some special effects with the help from the Vibration API. The best way to use it in our case is to vibrate the phone every time the ball hits the walls.

if("vibrate" in window.navigator) {
    window.navigator.vibrate(100);
}

If the vibrate method is supported by the browser and available in the window.navigator object, vibrate the phone for 100 miliseconds. That's it!

Adding the elapsed time

To improve the replayability and give players the option to compete with each other we can introduce the elapsed time. Thanks to this the player can play the given levels again and again trying to improve his score. To implement that in the game we have to create a variable for storing the actual number of seconds elapsed from the start of the game, and to show it for the player in the game. Let’s define the variable first:

this.timer = 0;
this.totalTimer = 0;

There are to variables to have the time elapsed in the current level and the time elapsed in the hole game. Then we can initialize the text objects:

this.timerText = this.game.add.text(15, 15, "Time: "+this.timer, this.fontBig);
this.totalTimeText = this.game.add.text(120, 30, "Total time: "+this.totalTimer, this.fontSmall);

We’re defining the top and left positions of the text, the content that will be showed and we can also apply font styling to the text, so it looks better. We have this printed out on the screen, but it would be good to update the values every second:

this.time.events.loop(Phaser.Timer.SECOND, this.updateCounter, this);

This loop will execute the updateCounter function in every single second from the beginning of the game, so we can apply the changes accordingly. This is how the updateCounter function looks like:

updateCounter: function() {
    this.timer++;
    this.timerText.setText("Time: "+this.timer);
    this.totalTimeText.setText("Total time: "+(this.totalTimer+this.timer));
},

As you can see we’re incrementing this.timer variable and updating the content of the text objects with the current values, so the player sees the elapsed time.

Finishing the level and the game

The ball is rolling on the screen, the time is running out, we have the hole that we have to reach, so let’s set up the possibility to actually finish the level. We will cover few aspects of the situation when the ball gets to the hole.

this.physics.arcade.overlap(this.ball, this.hole, this.finishLevel, null, this);

It works similar to the collide method explained earlier. When the ball overlap with the hole (instead of colliding), the finishLevel function is executed:

finishLevel: function() {
    if(this.level >= this.maxLevels) {
        this.totalTimer += this.timer;
        alert('Congratulations, game completed!\nTotal time of play: '+this.totalTimer+' seconds!');
        this.game.state.start('MainMenu');
    }
    else {
        alert('Congratulations, level '+this.level+' completed!');
        this.totalTimer += this.timer;
        this.timer = 0;
        this.level++;
        this.timerText.setText("Time: "+this.timer);
        this.totalTimeText.setText("Total time: "+this.totalTimer);
        this.levelText.setText("Level: "+this.level+" / "+this.maxLevels);
        this.ball.body.x = this.ballStartPos.x;
        this.ball.body.y = this.ballStartPos.y;
        this.ball.body.velocity.x = 0;
        this.ball.body.velocity.y = 0;
        this.showLevel();
    }
},

If the current level is equal to the maximum number of levels (in this case 5), then the game is finished - you'll get the congratulations message along with the number of seconds elapsed through the whole game. After clicking the alert button you are taken to the main menu. If the current level is lower though, all the neccesary variables are being reset and the next level is loaded.

Ideas for new features

This is merely a working demo of a game that could have lots of other different features. We can for example add power-ups to collect along the way that will make our ball roll faster, other can stop the timer for a few seconds or give the ball special powers to go through obstacles. There’s also room for the traps which will slow the ball down or make it more difficult to reach the hole. You can create more levels with the different difficulty for each one. You can even implement achievements, leaderboards and medals for different actions in the game. There are endless possibilities – they only depend on your imagination.

Summary

I hope this tutorial will help you dive into game development with Phaser and inspire you to create awesome games on your own. You can play the demo game Cyber Orb and check out its source code on GitHub. The technology gives us tools, the frameworks are getting faster and better, so you just have to start your own journey and see if HTML5 game development is something that you want to spend your time on.

Revision Source

<h2 id="Introduction">Introduction</h2>

<p>In this tutorial we’ll go through the process of building an HTML5 mobile game that uses the <strong>Device Orientation API</strong> and <strong>Vibration API</strong> in the gameplay and is built using the <strong>Phaser</strong> framework. Basic JavaScript knowledge is required to learn from the article below, and at the end of the tutorial we will have a fully functional demo game <a href="https://orb.enclavegames.com/">Cyber Orb</a>.</p>

<h2 id="Phaser_framework">Phaser framework</h2>

<p><a href="https://phaser.io/">Phaser</a> is a framework for building desktop and mobile HTML5 games. It’s quite new, but grows rapidly thanks to the passionate community involved in the development process. You can check it out <a href="https://github.com/photonstorm/phaser">on GitHub</a> where it’s open sourced, read the <a href="https://docs.phaser.io/">online documentation</a> and go through the big collection of <a href="https://examples.phaser.io/">examples</a>. The Phaser framework provide you with the set of tools that will speed up development and help handle generic tasks needed to complete the game, so you can focus on the game idea itself.</p>

<h2 id="Starting_with_the_project">Starting with the project</h2>

<p>You can see <a href="https://github.com/EnclaveGames/Cyber-Orb">the code of the project</a> on GitHub. The folder structure is quite straightforward: the starting point is the <code>index.html</code> file where we initialize the framework, set up the Canvas and play the game. You can click that file in your favourite browser to launch the game and try it. There are also three folders: <code>img</code>, <code>src</code> and <code>audio</code> - the first one contains all the images that we will use in the game, the second one have the JavaScript files with all the source code of the game defined inside, and in the third folder you can find the sound files used in the game.</p>

<h2 id="Setting_up_the_Canvas">Setting up the Canvas</h2>

<p>We will be rendering our game on Canvas, but we won't do it manually - it will be taken care of by the framework. Let’s set it up: our starting point is the <code>index.html</code> file with the following content:</p>

<pre class="brush: html">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="utf-8" /&gt;
    &lt;title&gt;Cyber Orb demo&lt;/title&gt;
    &lt;style&gt; body { margin: 0; background: #333; } &lt;/style&gt;
    &lt;script src="src/phaser-arcade-physics.2.2.2.min.js"&gt;&lt;/script&gt;
    &lt;script src="src/Boot.js"&gt;&lt;/script&gt;
    &lt;script src="src/Preloader.js"&gt;&lt;/script&gt;
    &lt;script src="src/MainMenu.js"&gt;&lt;/script&gt;
    &lt;script src="src/Howto.js"&gt;&lt;/script&gt;
    &lt;script src="src/Game.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;script&gt;
(function() {
    var game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game');
    game.state.add('Boot', Ball.Boot);
    game.state.add('Preloader', Ball.Preloader);
    game.state.add('MainMenu', Ball.MainMenu);
    game.state.add('Howto', Ball.Howto);
    game.state.add('Game', Ball.Game);
    game.state.start('Boot');
})();
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>

<p>It looks like a simple HTML website with some basic content in the <code>&lt;head&gt;</code> section: charset, title, CSS styling and the inclusion of the JavaScript files. The <code>&lt;body&gt;</code> contains initialization of the Phaser framework and the definitions of the game states. You can check the <a href="https://gamedevelopment.tutsplus.com/tutorials/getting-started-with-phaser-building-monster-wants-candy--cms-21723">Building Monster Wants Candy</a> article for the in-depth introduction to the basic Phaser-specific functions and methods.</p>

<h2 id="Managing_game_states">Managing game states</h2>

<p>The states in Phaser are a separate parts of the game logic, in our case we’re loading them from independent JavaScript files for better maintainability. The basic states used in this game are: <code>Boot</code>, <code>Preloader</code>, <code>MainMenu</code>, <code>Howto</code> and <code>Game</code>. <code>Boot</code> will take care of initializing a few settings, <code>Preloader</code> will load all of the assets like graphics and audio, <code>MainMenu</code> is the menu with the start button, <code>Howto</code> shows how to play instructions and the <code>Game</code> state lets you actually play the game. Let's quickly go though the content of those states.</p>

<h2 id="Boot.js">Boot.js</h2>

<p>The <code>Boot</code> state is the first one in the game.</p>

<pre class="brush: js">
var Ball = {
    _WIDTH: 320,
    _HEIGHT: 480
};
Ball.Boot = function(game) {};
Ball.Boot.prototype = {
    preload: function() {
        this.load.image('preloaderBg', 'img/loading-bg.png');
        this.load.image('preloaderBar', 'img/loading-bar.png');
    },
    create: function() {
        this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
        this.game.scale.pageAlignHorizontally = true;
        this.game.scale.pageAlignVertically = true;
        this.game.state.start('Preloader');
    }
};</pre>

<p>The main <code>Ball</code> object is defined and we're adding two variables called <code>_WIDTH</code> and <code>_HEIGHT</code> that are the width and the height of the game Canvas - they will help us position elements on the screen. We're loading two images first that will be used later in the <code>Preload</code> state to show the progress of loading all the other assets. The <code>create</code> function holds some basic configuration: we're setting up the scaling and alignment of the Canvas, and moving on to the <code>Preload</code> state when everything's ready.</p>

<h2 id="Preloader.js">Preloader.js</h2>

<p>The <code>Preloader</code> state takes care of loading all the assets:</p>

<pre class="brush: js">
Ball.Preloader = function(game) {};
Ball.Preloader.prototype = {
    preload: function() {
        this.preloadBg = this.add.sprite((Ball._WIDTH-297)*0.5, (Ball._HEIGHT-145)*0.5, 'preloaderBg');
        this.preloadBar = this.add.sprite((Ball._WIDTH-158)*0.5, (Ball._HEIGHT-50)*0.5, 'preloaderBar');
        this.load.setPreloadSprite(this.preloadBar);

        this.load.image('ball', 'img/ball.png');
        // ...
        this.load.spritesheet('button-start', 'img/button-start.png', 146, 51);
        // ...
        this.load.audio('audio-bounce', ['audio/bounce.ogg', 'audio/bounce.mp3', 'audio/bounce.m4a']);
    },
    create: function() {
        this.game.state.start('MainMenu');
    }
};</pre>

<p>There are single images, spritesheets and audio files loaded by the framework. In this state the <code>preloadBar</code> is showing the progress on the screen. After all the assets are loaded, the <code>MainMenu</code> state is launched.</p>

<h2 id="Main_menu">Main menu</h2>

<p>The <code>MainMenu</code> state shows the main menu of the game where you can start playing by clicking the button.</p>

<pre class="brush: js">
Ball.MainMenu = function(game) {};
Ball.MainMenu.prototype = {
    create: function() {
        this.add.sprite(0, 0, 'screen-mainmenu');
        this.gameTitle = this.add.sprite(Ball._WIDTH*0.5, 40, 'title');
        this.gameTitle.anchor.set(0.5,0);
        this.startButton = this.add.button(Ball._WIDTH*0.5, 200, 'button-start', this.startGame, this, 2, 0, 1);
        this.startButton.anchor.set(0.5,0);
        this.startButton.input.useHandCursor = true;
    },
    startGame: function() {
        this.game.state.start('Howto');
    }
};</pre>

<p>Instead of jumping directly into the action, the game will show the screen with the information on how to play the game.</p>

<h2 id="How_to_play">How to play</h2>

<pre class="brush: js">
Ball.Howto = function(game) {
};
Ball.Howto.prototype = {
    create: function() {
        this.buttonContinue = this.add.button(0, 0, 'screen-howtoplay', this.startGame, this);
    },
    startGame: function() {
        this.game.state.start('Game');
    }
};</pre>

<p>The Howto state is showing the gameplay instructions on the screen before starting the game. After clicking the screen the actual game is launched.</p>

<h2 id="The_Game">The Game</h2>

<p>The <code>Game</code> state from the <code>Game.js</code> file is where all the magic happen. All the initialization is in the <code>create()</code> function (launched once at the beginning of the game), some things will require adding them to the <code>update()</code> function (executed at every frame), and we will also write our own functions to handle more complicated tasks.</p>

<pre class="brush: js">
Ball.Game = function(game) {};
Ball.Game.prototype = {
    create: function() {},
    initLevels: function() {},
    showLevel: function(level) {},
    updateCounter: function() {},
    managePause: function() {},
    manageAudio: function() {},
    update: function() {},
    wallCollision: function() {},
    handleOrientation: function(e) {},
    finishLevel: function() {}
};</pre>

<p>The <code>create</code> and <code>update</code> functions are framework-specific, while others are our own creations: <code>initLevels</code> initializes the level data, <code>showLevel</code> prints the level data on the screen, <code>updateCounter</code> updates the time spent on playing the game, <code>managePause</code> pauses and resumes the game, <code>manageAudio</code> turns the sounds on and off, <code>wallCollision</code> is executed when the ball hits the walls or other objects, <code>handleOrientation</code> is the function bound to the event responsible for the <strong>Device Orientation API</strong> and <code>finishLevel</code> is loading a new level if there is any, or finishing the game.</p>

<h2 id="Adding_the_ball_and_its_motion_mechanics">Adding the ball and its motion mechanics</h2>

<p>First, let’s go to the <code>create</code> function, initialize the ball object itself and assign a few properties to it:</p>

<pre class="brush: js">
this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, 'ball');
this.ball.anchor.set(0.5);
this.physics.enable(this.ball, Phaser.Physics.ARCADE);
this.ball.body.setSize(18, 18);
this.ball.body.bounce.set(0.3, 0.3);</pre>

<p>We’re adding a sprite at the given place on the screen and using the <code>'ball'</code> image from the loaded graphic assets. We’re also setting the anchor of any physic calculations to the middle of the ball, then enabling the ball for the Arcade physics engine, and setting the size of the body for the collision detection. The <code>bounce</code> property is used to set the bounciness of the ball when it hits the obstacles.</p>

<h2 id="Controlling_the_ball">Controlling the ball</h2>

<p>It’s cool to have the ball ready to be thrown around the play area, but it’s also important to be able to do it. Now we will add the ability to control the ball with the keyboard on the desktop devices, and then we will move to the implementation of the Device Orientation API. Let’s focus on the keyboard first:</p>

<pre class="brush: js">
this.keys = this.game.input.keyboard.createCursorKeys();</pre>

<p>As you can see there’s a special Phaser function which will give us an object with the four arrow keys to play with: up, down, left and right. The <code>this.keys</code> object will then be checked against player input, so the ball can react accordingly with the prefedined force:</p>

<pre class="brush: js">
if(this.keys.left.isDown) {
    this.ball.body.velocity.x -= this.movementForce;
}
else if(this.keys.right.isDown) {
    this.ball.body.velocity.x += this.movementForce;
}
if(this.keys.up.isDown) {
    this.ball.body.velocity.y -= this.movementForce;
}
else if(this.keys.down.isDown) {
    this.ball.body.velocity.y += this.movementForce;
}</pre>

<p>The code above is in the <code>update</code> function, so it will be fired on every frame. That way we can check which key is pressed at the given frame and apply the defined force to the ball, thus increase the velocity in the proper direction.</p>

<h2 id="Implementing_the_Device_Orientation_API">Implementing the Device Orientation API</h2>

<p>The interesting part of the game is that it uses <strong>Device Orientation API</strong> on mobile devices. Thanks to this you can play the game by tilting the device in the direction you want the ball to roll. Here’s the code responsible for this:</p>

<pre class="brush: js">
window.addEventListener("deviceorientation", this.handleOrientation, true);</pre>

<p>We’re adding an event listener to the <code>"deviceorientation"</code> event and binding the <code>handleOrientation</code> function which looks like this:</p>

<pre class="brush: js">
handleOrientation: function(e) {
    var x = e.gamma;
    var y = e.beta;
    Ball._player.body.velocity.x += x;
    Ball._player.body.velocity.y += y;
},</pre>

<p>The more you tilt the device, the more force is applied to the ball and the velocity is higher.</p>

<h2 id="Adding_the_hole">Adding the hole</h2>

<p>Our main purpose of the game is to move the ball from the starting position to the ending position which in our case will be a hole in the ground. Implementation looks very similar to the part where we created the ball:</p>

<pre class="brush: js">
this.hole = this.add.sprite(Ball._WIDTH*0.5, 90, 'hole');
this.physics.enable(this.hole, Phaser.Physics.ARCADE);
this.hole.anchor.set(0.5);
this.hole.body.setSize(2, 2);</pre>

<p>The difference is that our hole’s body will not move when we hit it with the ball and will have the collision detection calculated (which will be discussed further in this article).</p>

<h2 id="Building_the_block_labyrinth">Building the block labyrinth</h2>

<p>To make the game harder and more interesting we should build some obstacles on the way from the starting point to the end of the level, so let's build a labyrinth. We could use a level editor, but for the sake of this tutorial let's create something on our own.</p>

<p>We'll have a level data holding the information of the particular blocks - the top and left absolute positions in pixels and the type of the block - horizontal or vertical. Then, to load the level we need we will parse the data and show the blocks specific for that level. In the <code>initLevels</code> function we have:</p>

<pre class="brush: js">
this.levelData = [
    [
        { x: 96, y: 224, t: 'w' }
    ],
    [
        { x: 72, y: 320, t: 'w' },
        { x: 200, y: 320, t: 'h' },
        { x: 72, y: 150, t: 'w' }
    ],
    // ...
];</pre>

<p>Every array element holds the collection of the blocks with the <code>x</code>, <code>y</code> position and <code>t</code> type. In the loop we're creating the items using the framework:</p>

<pre class="brush: js">
for(var i=0; i&lt;this.maxLevels; i++) {
    var newLevel = this.add.group();
    newLevel.enableBody = true;
    newLevel.physicsBodyType = Phaser.Physics.ARCADE;
    for(var e=0; e&lt;this.levelData[i].length; e++) {
        var item = this.levelData[i][e];
        newLevel.create(item.x, item.y, 'element-'+item.t);
    }
    newLevel.setAll('body.immovable', true);
    newLevel.visible = false;
    this.levels.push(newLevel);
}</pre>

<p>Everything is stored in <code>this.levels</code> array, and is by default invisible. Then, to load specific level we just have to make sure the previous level is hidden and show the current one:</p>

<pre class="brush: js">
showLevel: function(level) {
    var lvl = level | this.level;
    if(this.levels[lvl-2]) {
        this.levels[lvl-2].visible = false;
    }
    this.levels[lvl-1].visible = true;
}</pre>

<p>Thanks to that the game gives the player a challenge - now he have to roll the ball across the play area and guide it through the labyrinth built from the blocks. It's just an example of loading the levels, and there are only 5 of them just to showcase the idea, but you can work on expanding that on your own.</p>

<h2 id="Collision_detection">Collision detection</h2>

<p>We have the ball that is controlled by the player, the hole to reach and the obstacles blocking the way. There’s a problem though – our game don’t have the collision detection yet, so nothing happens when the ball hits the blocks, it just goes through. That’s not the effect we wanted to achieve, so let’s work on it. The good news is that the framework will take care of calculating the collision detection, we only have to specify the colliding objects:</p>

<pre class="brush: js">
this.physics.arcade.collide(this.ball, this.borderGroup, this.wallCollision, null, this);
this.physics.arcade.collide(this.ball, this.levels[this.level-1], this.wallCollision, null, this);</pre>

<p>This will tell the framework to execute the <code>wallCollision</code> function when the ball will hit any of the walls. We can use the <code>wallCollision</code> function to add any functionality we want like playing the bounce sound or implementing the <strong>Vibration API</strong>.</p>

<h2 id="Adding_the_sound">Adding the sound</h2>

<p>Among the preloaded assets there was an audio file (in various formats for browser compatibility) which we can use now. It have to be defined in the <code>create</code> function first:</p>

<pre class="brush: js">
this.bounceSound = this.game.add.audio('audio-bounce');</pre>

<p>Then, if the status of the audio is <code>true</code> (so the sounds in the game are enabled), we can play it in the <code>wallCollision</code> function:</p>

<pre class="brush: js">
if(this.audioStatus) {
    this.bounceSound.play();
}</pre>

<p>That's all - loading and playing the sounds is easy with Phaser.</p>

<h2 id="Implementing_the_Vibration_API">Implementing the Vibration API</h2>

<p>When collision detection works as expected let's add some special effects with the help from the Vibration API. The best way to use it in our case is to vibrate the phone every time the ball hits the walls.</p>

<pre class="brush: js">
if("vibrate" in window.navigator) {
    window.navigator.vibrate(100);
}</pre>

<p>If the <code>vibrate</code> method is supported by the browser and available in the <code>window.navigator</code> object, vibrate the phone for 100 miliseconds. That's it!</p>

<h2 id="Adding_the_elapsed_time">Adding the elapsed time</h2>

<p>To improve the replayability and give players the option to compete with each other we can introduce the elapsed time. Thanks to this the player can play the given levels again and again trying to improve his score. To implement that in the game we have to create a variable for storing the actual number of seconds elapsed from the start of the game, and to show it for the player in the game. Let’s define the variable first:</p>

<pre class="brush: js">
this.timer = 0;
this.totalTimer = 0;</pre>

<p>There are to variables to have the time elapsed in the current level and the time elapsed in the hole game. Then we can initialize the text objects:</p>

<pre class="brush: js">
this.timerText = this.game.add.text(15, 15, "Time: "+this.timer, this.fontBig);
this.totalTimeText = this.game.add.text(120, 30, "Total time: "+this.totalTimer, this.fontSmall);</pre>

<p>We’re defining the top and left positions of the text, the content that will be showed and we can also apply font styling to the text, so it looks better. We have this printed out on the screen, but it would be good to update the values every second:</p>

<pre class="brush: js">
this.time.events.loop(Phaser.Timer.SECOND, this.updateCounter, this);</pre>

<p>This loop will execute the <code>updateCounter</code> function in every single second from the beginning of the game, so we can apply the changes accordingly. This is how the <code>updateCounter</code> function looks like:</p>

<pre class="brush: js">
updateCounter: function() {
    this.timer++;
    this.timerText.setText("Time: "+this.timer);
    this.totalTimeText.setText("Total time: "+(this.totalTimer+this.timer));
},</pre>

<p>As you can see we’re incrementing <code>this.timer</code> variable and updating the content of the text objects with the current values, so the player sees the elapsed time.</p>

<h2 id="Finishing_the_level_and_the_game">Finishing the level and the game</h2>

<p>The ball is rolling on the screen, the time is running out, we have the hole that we have to reach, so let’s set up the possibility to actually finish the level. We will cover few aspects of the situation when the ball gets to the hole.</p>

<pre class="brush: js">
this.physics.arcade.overlap(this.ball, this.hole, this.finishLevel, null, this);</pre>

<p>It works similar to the <code>collide</code> method explained earlier. When the ball overlap with the hole (instead of colliding), the <code>finishLevel</code> function is executed:</p>

<pre class="brush: js">
finishLevel: function() {
    if(this.level &gt;= this.maxLevels) {
        this.totalTimer += this.timer;
        alert('Congratulations, game completed!\nTotal time of play: '+this.totalTimer+' seconds!');
        this.game.state.start('MainMenu');
    }
    else {
        alert('Congratulations, level '+this.level+' completed!');
        this.totalTimer += this.timer;
        this.timer = 0;
        this.level++;
        this.timerText.setText("Time: "+this.timer);
        this.totalTimeText.setText("Total time: "+this.totalTimer);
        this.levelText.setText("Level: "+this.level+" / "+this.maxLevels);
        this.ball.body.x = this.ballStartPos.x;
        this.ball.body.y = this.ballStartPos.y;
        this.ball.body.velocity.x = 0;
        this.ball.body.velocity.y = 0;
        this.showLevel();
    }
},</pre>

<p>If the current level is equal to the maximum number of levels (in this case 5), then the game is finished - you'll get the congratulations message along with the number of seconds elapsed through the whole game. After clicking the alert button you are taken to the main menu. If the current level is lower though, all the neccesary variables are being reset and the next level is loaded.</p>

<h2 id="Ideas_for_new_features">Ideas for new features</h2>

<p>This is merely a working demo of a game that could have lots of other different features. We can for example add power-ups to collect along the way that will make our ball roll faster, other can stop the timer for a few seconds or give the ball special powers to go through obstacles. There’s also room for the traps which will slow the ball down or make it more difficult to reach the hole. You can create more levels with the different difficulty for each one. You can even implement achievements, leaderboards and medals for different actions in the game. There are endless possibilities – they only depend on your imagination.</p>

<h2 id="Summary">Summary</h2>

<p>I hope this tutorial will help you dive into game development with Phaser and inspire you to create awesome games on your own. You can play the demo game <a href="https://orb.enclavegames.com/">Cyber Orb</a> and check out its <a href="https://github.com/EnclaveGames/Cyber-Orb">source code on GitHub</a>. The technology gives us tools, the frameworks are getting faster and better, so you just have to start your own journey and see if HTML5 game development is something that you want to spend your time on.</p>
Revert to this revision