How to Make A Sidescroller Game with HTML5

by Pablo Farias Navarro

Casual, simple 2D games can sometimes be more popular that overly complex million dollar productions. This is not either a good or a bad thing, it’s just how people choose to spend their free time.

When it comes to games, fun is what determines whether you keep on playing or not. Assuming, of course, that the game is available on the device you own!

Availability in many platforms and devices is thus an important aspect to consider. I focus on HTML5 not just because I love it, but also because it allows me to target many different platforms with a single code base, leveraging my existing web development skills.

In this tutorial, you’ll learn the basics of HTML5 mobile game development using the Phaser library, by creating a simple side-scroller mobile/cross-platform game from scratch.

Feel free to use the provided code and assets (they are public domain) as a starter for your own mobile projects!

Source code files

Download the source code and game assets in a zip file. You can also get them from Github. If you are impatient you can checkout the finished game here.

Tutorial goals

If you follow this tutorial through you should have a pretty solid base to create 2D mobile HTML5 games with Phaser.

1. Learn the basics of Phaser by creating a 2d side-scroller.

2. Learn how to use the free Tiled level editor to create levels for your HTML5 games.

3. Learn some basic 2D game mechanics.

Tutorial requirements

  • Basic to intermediate knowledge of JavaScript*. If you need a refreshment feel free to check my online course on basic JavaScript.
  • A code editor or IDE. Some options include Sublime Text, Netbeans, or lightweight alternatives like Geany. You can also check out the Intel® XDK.
  • Download Phaser from its GitHub repo. You can either clone the repo or download the ZIP file.
  • You need to run the code and the Phaser examples using a local or remote web server. Some popular options are Apache (WAMP if in Windows, MAMP if in Mac). A lightweight alternatives are Mongoose web server and Python’s HTTP server. Take a look at this guide for more details.
  • Have the Phaser documentation and the examples page at hand. Also don’t forget that you can always find answers by looking at the source code of Phaser.
  • We’ll be making a tile-based game for which we’ll use the free and Open Source Tiledmap editor, compatible with Windows, Mac and Linux.
  • For the touch control we’ll use a library called HTML5 Virtual Game Controller. The file gamecontroller.js comes included in the game code, but feel free to grab the latest version and read it’s documentation.

New project

Let’s begin with a new folder, an index HTML file and the Phaser file, which you can grab from the “build” directory of the downloaded Phaser zip or cloned repository.

If you are on development mode (as opposed to production, which would be deploying your game to it’s final destination for the world to play it) I recommend including the non-minified phaser.js file (as opposed to phaser.min.js). The reason being, it’s not a good practice to treat your game engine as a black box. You want to be able to explore the contents of the file and debug properly.

Not all the answers will be on Google or StackOverflow so a lot of times the best way to do is just read the original source code to understand what’s going on! Our index.html file will look like this. We’ll be adding and explaining the files you see here as the tutorial progresses:

<!DOCTYPE html>
 
<html>
 
  <head>
 
    <meta charset="utf-8" />
 
    <title>Learn Game Development at ZENVA.com</title>
 
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
    <meta name="mobile-web-app-capable" content="yes">
 
    <meta name="apple-mobile-web-app-capable" content="yes">
 
    <script type="text/javascript" src="js/gamecontroller.js"></script>
 
    <script type="text/javascript" src="js/phaser.min.js"></script>
 
    <script type="text/javascript" src="js/Boot.js"></script>
 
    <script type="text/javascript" src="js/Preload.js"></script>
 
    <script type="text/javascript" src="js/Game.js"></script>
 
    <style>
 
      body {
 
        padding: 0px;
 
        margin: 0px;
 
      }
 
      </style>
 
  </head>
 
  <body> 
 
    <!-- include the main game file -->
 
    <script src="js/main.js"></script>
 
  </body>
 
</html>

We are using the viewport metatag to prevent the user from zooming if they pinch they screen (which they could always accidentally do when playing). By adding the mobile-web-app-capable and apple- mobile-web-app-capable we are allowing mobile phone users to add a shortcut to their phones to the webapp (you can also add an icon, read more for iOS and Android Chrome).

The file main.js will initiate our game.

States

Before moving forward with the code I’d like to talk about States, an important concept in Phaser.

In Phaser, all the action occurs around States. You can think of them as main moments of your game. Think of a soccer game, you have a State when doors are open and people start coming in. Then you have a State when the pre-game show takes place. Then a State where the pre-game show stuff is removed from the field. Then a State when the game begins, and so forth.

Phaser gives you a lot of flexibility as what States you can have, but there is a de-facto convention which is used in many games and tutorials. The naming might vary a bit but it’s usually something like:

Boot State: general game settings are defined, and the assets of the preloading screen are loaded (example the loading bar). Nothing is shown to the user.

Preload State: the game assets (images, spritesheets, audio, textures, etc) are loaded into the memory (from the disk). The preloading screen is shown to the user, which usually includes a loading bar to show the progress.

MainMenu State: your game’s welcome screen. After the preload state, all the game images are already loaded into the memory, so they can quickly accessed.

Game State: the actual game where the FUN takes place.

In our tutorial we’ll only use three states: Boot, Preload and Game. You can learn how to add a MainMenu state in my tutorial HTML5 Phaser Tutorial – SpaceHipster, a Space Exploration Game.

Initiating the game

Ok back to coding! Lets take a look at main.js, the entry point of the game:

var SideScroller = SideScroller || {};
 
SideScroller.game = new Phaser.Game(746, 420, Phaser.AUTO, '');
 
SideScroller.game.state.add('Boot', SideScroller.Boot);
 
SideScroller.game.state.add('Preload', SideScroller.Preload);
 
SideScroller.game.state.add('Game', SideScroller.Game);
 
SideScroller.game.state.start('Boot');

The first thing we do is create an object that will keep all the data from our game. We are calling this object SideScroller.

Now why exactly am I doing that? why not just create a variable called game, then create new variables for the other objects we’ll be defining in each file?

The truth is you can do that too is you so prefer, but it’s good practice to keep everything in one single object. This is called the namespace pattern. What you generally don’t want to do is pollute the global scope of your application. Imagine I’m including an external library which also happens to define a variable called “game”. The more variables you create in the global scope, the more likely this could happen. This could make your game to malfunction. So we usually pick a name that’s very unlikely to be used elsewhere such as “SideScroller” and put everything inside of it.

The statement: var SideScroller = SideScroller || {}; means if SideScroller is not defined previously, it will be created as an empty object.

In this line:

SideScroller.game = new Phaser.Game(746, 420, Phaser.AUTO, ”);

We are initiating our Phaser game with a screen resolution. In order to render your game, Phaser can use a CANVAS element or do it on WebGL (a specification to work with OpenGL en the web, present in most modern browsers). By setting the rendering to Phaser.AUTO we let Phaser decide what to use according to what’s available.

After defining our states (those objects will be created in external files) we tell Phaser to launch the Boot state.

States methods

States have some reserved methods which serve specific purposes. These are the ones we’ll use in this tutorial. You can find the full list here.

-init: is called upon State initialization. If you need to send parameters to the State this is where they’ll be accessible (more on that later)

-preload: this is where the assets are loaded.

-create: this is called upon asset loading completion.

-update: this is called on every game tick. Basically it’s called “many times per second” so this is where you want to include things that need to be constantly tested such as collision detection.

Boot state

Before talking about the Boot state I’d like to say that in theory, you could not use states where all the game takes place, but using states allows you to organize your code better.

The Boot state is a dark place. This is where we define the screen size and other general game configuration options such as the physics engine we’ll use (Phaser has three of them, we’ll use the simplest one called Arcade). Also, in the Boot state we load the assets that will be shown in the Preload state.

So.. the Boot state loads the assets for the Preload state, and the Preload state loads the game assets. It’s sounding like “a dream within a dream” isn’t it? you might think, why instead not load the game assets there? Well nothing stops you from doing that, but the thing is, the game assets will most likely take much longer to load than the preload screen assets, which should be nothing but a loading bar and maybe a logo.

By loading the preloading screen assets first (which, again, should be lightweight) we minimize the time where there will be a blank screen (better than a blue screen, but users don’t love it). Then, on the Preload state we’ll have time to load everything else with a nice and charming preload screen that keeps the eye busy.

Content of Boot.js:

var SideScroller = SideScroller || {};
 
SideScroller.Boot = function(){};
 
//setting game configuration and loading the assets for the loading screen
 
SideScroller.Boot.prototype = {
 
  preload: function() {
 
    //assets we'll use in the loading screen
 
    this.load.image('preloadbar', 'assets/images/preloader-bar.png');
 
  },
 
  create: function() {
 
    //loading screen will have a white background
 
    this.game.stage.backgroundColor = '#fff';
 
    //scaling options
 
    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
 
    //have the game centered horizontally
 
    this.scale.pageAlignHorizontally = true;
 
    this.scale.pageAlignVertically = true;
 
    //screen size will be set automatically
 
    this.scale.setScreenSize(true);
 
    //physics system
 
    this.game.physics.startSystem(Phaser.Physics.ARCADE);
 
    this.state.start('Preload');
 
  }
 
};

We start by following the same pattern as in main.js. If SideScroller is already defined, we use it, otherwise we initiate a new object.

SideScroller.Boot is the object that will contain the Boot state. This is the same object we passed in main.js when adding the state to the game:

SideScroller.game.state.add('Boot', SideScroller.Boot);

On the preload method we are loading the sprite for the progress bar, which is simply a green rectangle. By loading an image like this:

this.load.image('preloadbar', 'assets/images/preloader-bar.png');

We can reference that image asset anywhere in the game by using it’s key, in this case “preloadbar”.

In the create method we are defining some general options such as the screen scaling. Phaser provides three options of scaling for the game size we defined in main.js: EXACT_FIT (stretching the game to cover all the area), SHOW_ALL (scaling the game keeping the aspect ratio) and NO_SCALE (no scale!). In our case we’ll use SHOW_ALL (my preferred one).

(Images are screenshots from my retro game Huungree RPG, proudly built with HTML5 foriOS and Android)

We want our game to be centered both horizontally and vertically:

this.scale.pageAlignHorizontally = true;
 
this.scale.pageAlignVertically = true;
 
Now, the game area we defined in main.js:
 
SideScroller.game = new Phaser.Game(746, 420, Phaser.AUTO, '');

Represents the pixels in the game. They will also represent the pixels on the screen, but most of the time you want the game to fit the entire screen, that’s why we are adding this line:

this.scale.setScreenSize(true);
 
Lastly, we initiate the physics engine and launch the Preload state:
 
this.game.physics.startSystem(Phaser.Physics.ARCADE);
 
this.state.start('Preload');

Preload state

The Preload state is where all the game assets are loaded. This includes images, audio, tilemaps and any other files you want to have available in your game.

Why do we need to preload assets?

Whether you are loading files from the web or from the a hard drive, that takes time. You don’t want your players to shoot a bullet and find out the bullet sprite is taking a minute to load so your game gets stuck or it doesn’t show the image it should be showing. By preloading, what we are doing is loading all these files to your device’s RAM, from which your game can quickly access any image/resource as needed. It’s best to make your player wait at the beginning than giving them a terrible experience!

var SideScroller = SideScroller || {};
 
//loading the game assets
 
SideScroller.Preload = function(){};
 
SideScroller.Preload.prototype = {
 
  preload: function() {
 
    //show loading screen
 
    this.preloadBar = this.add.sprite(this.game.world.centerX, this.game.world.centerY, 'preloadbar');
 
    this.preloadBar.anchor.setTo(0.5);
 
    this.preloadBar.scale.setTo(3);
 
    this.load.setPreloadSprite(this.preloadBar);
 
    //load game assets
 
    this.load.tilemap('level1', 'assets/tilemaps/level1.json', null, Phaser.Tilemap.TILED_JSON);
 
    this.load.image('gameTiles', 'assets/images/tiles_spritesheet.png');
 
    this.load.image('player', 'assets/images/player.png');
 
    this.load.image('playerDuck', 'assets/images/player_duck.png');
 
    this.load.image('playerDead', 'assets/images/player_dead.png');
 
    this.load.image('goldCoin', 'assets/images/goldCoin.png');
 
    this.load.audio('coin', 'assets/audio/coin.wav');
 
  },
 
  create: function() {
 
    this.state.start('Game');
 
  }
 
};

The first part consists on the creation of a sprite called “preloadBar”, which is placed at the center of the game area and uses the image with key “preloadbar”, that we previously loaded in the Boot state. Read more about the Sprite class in the documentation.

What we do then is set the anchor point of the image to it’s middle. Imagine you make an image grow, shrink or rotate. The anchor point is the point that will remain in the same part of the screen after this transformation happens.

Since the bar is a bit small we make it grow 3 times it’s size:

this.preloadBar.scale.setTo(3);

Phaser allows us to specify any sprite as a preload bar, that will basically grow until full size as the game elements get loaded:

this.load.setPreloadSprite(this.preloadBar);

Afterwards, we load all the elements. When the loading is completed we move to the Game state.

You should be seeing the loading bar at this point if you comment out the reference to SideScroller.Game in main.js

Game State

We still need to talk about tile-based games and the Tiled map editor, but let’s put on a skeleton for Game.js so that we can now fully run the game without console errors:

var SideScroller = SideScroller || {};
 
SideScroller.Game = function(){};
 
SideScroller.Game.prototype = {
 
  preload: function() {
 
      this.game.time.advancedTiming = true;
 
    },
 
  create: function() {
 
    //create player
 
    this.player = this.game.add.sprite(100, 300, 'player');
 
 }, 
 
  update: function() {
 
  },
 
  render: function()
 
    {
 
        this.game.debug.text(this.game.time.fps || '--', 20, 70, "#00ff00", "40px Courier");  
 
    }
 
};

We are doing two things here: on create, we are creating a sprite for the player, using the image that we called “player” in Preload.

Secondly, we are showing the frames per second (fps) of our game by initiative the timer here:

this.game.time.advancedTiming = true;

And then showing the debug text on the render method. Phaser does it’s best to run at 60 fps. The closer you can get to that number the better. It’s really hard that HTML5 games run at this rate nowadays, even on fairly decent phones and computers, but it’s improving more and more. I like to keep this number on just to keep an eye on the performance and to detect in what situations that number drops (a bad thing).

Read more about debugging on the documentation.

To move any further we have to talk about Tiled.

Get Tiled-face

Tiled is a really awesome level editor created by Thorbjørn Lindeijer which allows you to visually create tile-based levels for your games. The main file format these levels use is called TMX and it’s XML. In order to use these levels in Phaser we’ll to export them as JSON files.

When I talk about “tiles” and “tiled-based games” what I mean are games where the levels are composed of individual small blocks or pieces. Check out the Wikipedia definition if you are not 100% familiar with this concept.

To create a new map in Tiled go to File -> New:

Our level will have a width of 50 tiles and a height of 6 tiles. The size of these tiles is 70×70 pixels. Make sure Orientation is set to “Orthogonal” and Layer format to “CSV”.

A word of advise regarding performance: the larger your map, the worst the performance. Try not to make your maps unnecessarily large. Also, the smaller the tile size the better. Even 70 is a bit too big. Same goes to the size of your game area. The only way to know is to try it out and if it’s laggy and slow, reduce until the game runs well.

The next step is to create the Layers. A level will have different layers that sit on top of each other. The naming of the layers is important here as we need to refer to that in the code later on.

There are two types of layers:

  • Tile layer: layer made of tiles/blocks.
  • Objects layer: layer where you create vector objects that can contain metadata.

You can create layers using the “+” button under layers, to rename them just click on the name of the newly created layers. The order matters, you can rearrange them using the arrows.

In our example we’ll have two tile layers: one for the background called backgroundLayer (doesn’t collide with the player) and one for the blocking elements called blockedLayer (floor, walls). We’ll also have one objects layer (objectsLayer) that will represent game elements, in this case the coins, but it could also be enemies, door, the player starting position (see my tutorial HTML5 Phaser Tutorial – Top-Down Games with Tiled for more examples).

This is all just a suggestion and how I normally do it, it is by no means a convention or a rule of the framework!

Loading the tileset

A tileset is a set of individual tiles, which come in an image. You can have many tilesets on your tilemaps. We’ll use just one: assets/images/tiles_spritesheet.png. This tileset is public domain (you can use it for your own commercial projects) and was created by Kenney.

To load a tileset: Map -> New Tileset

The width and height of the tiles is 70 pixels (try to use smaller if you can, the smaller the better for performance!). The separation between the tiles is 2 pixels, therefore I entered 2 for Spacing.

See that for Name we just left it as tiles_spritesheets. Keep this name in your head as we’ll use it to refer to the tilesheet within Phaser.

Create the level

You can now create your level. Now it’s really up to you! What I did was fill the backgroundLayer with a an pink tile to represent the sky of an alien world (using the bucket tool), then changed to the blockedTile and painted some floor and obstacles.

The object layer

In this tutorial we’ll only add one type of object here, but you could add as many as you want following a similar approach.

These objects will be represented by sprites from the tileset, but that is just for OUR simplicity. Phaser will show the sprite you tell it to when creating a Sprite object.

Let me explain this better. In the file tiles_spritesheet.png I added the coin and I’ll be placing objects that use this image in the level. Instead of adding the coin image, I could have added say a tile with the letter “C”. It doesn’t matter. Phaser will load what you tell you to, but it’s of course easier if you can visualize how your level will really look like.

To insert new objects: select the objectsLayer layer, click on the Insert Tile button (the one that shows a picture of the sunset) then click on the tile you want to show, then click on the location of the object within the map.

Adding properties to the objects

How is Phaser going to know what these elements represent and what sprite should be used to display them? Lets add that as object properties.

Click on the “Select object” button from the menu, then double click on any object and you’ll see a dialog where you can enter properties.

Enter a property called “type” with value “coin”. Set another property called “sprite” and enter “coin”. This will tell Phaser what image it should use for this object (we loaded a coin image in Preload and called it “coin”, that’s why we enter “coin” here).

You could enter more properties depending on your game (it’s really up to you!). For example “value” to give different coins different value, or you could use different sprites for coin objects if you specify a different “sprite” value here.

In order to create multiple elements, you can right click on the coin you created and click “duplicate”, this will allow you to quickly replicate an object along with it’s properties. You can clone multiple coins and drag them around the level.

Before we move any further, I’d like to make it clear that this will work with the game template we are building in this tutorial (and some of my other tutorials), it is not a default Phaser functionality. Phaser only provides the ability to create several sprites from objects using the same sprite key. Take a look at the Tilemap documentation to learn what Phaser provides in this aspect.

Once you are doing export the level as a JSON file. File -> Export As -> Json Files, save into /assets/tilemaps/level1.json

Loading the tilemap into the game

A quick overview of this process would be:

  1. Preload the tileset png file and the level JSON file (at this point, Phaser doesn’t know they belong together).
  2. Create the tilemap on the Game statement
  3. Add the tileset to the tilemap (basically merging the JSON data with the actual images, so that Phaser knows that they go together)
  4. Add the tile layers to the tilemap (backgroundLayer and blockedLayer)
  5. Make the blockedLayer a collision layer
  6. Resize the game world to have the same size as the level we created in tiled-based
  7. Create the game objects based on what’s on the layer objectsLayer (in this tutorial, just the coins)

Let’s start by reviewing what we loaded in the Preload state in regards to the tile map:

this.load.tilemap('level1', 'assets/tilemaps/level1.json', null, Phaser.Tilemap.TILED_JSON);
 
this.load.image('gameTiles', 'assets/images/tiles_spritesheet.png');

Feel free to explore further on the documentation page for the Loader. Keep in your head the keys “level1″ and “gameTiles”, which are completely arbitrary and it’s what we’ll use later to refer to these assets.

Now we’ll add the following to Game.js, in the create method, before the creation of the player:

this.map = this.game.add.tilemap('level1');
 
    //the first parameter is the tileset name as specified in Tiled, the second is the key to the asset
 
    this.map.addTilesetImage('tiles_spritesheet', 'gameTiles');
 
    //create layers
 
    this.backgroundlayer = this.map.createLayer('backgroundLayer');
 
    this.blockedLayer = this.map.createLayer('blockedLayer');
 
    //collision on blockedLayer
 
    this.map.setCollisionBetween(1, 100000, true, 'blockedLayer');
 
    //resizes the game world to match the layer dimensions
 
    this.backgroundlayer.resizeWorld();

The first three statements are self-explanatory after the steps description. The statement for the collision:

this.map.setCollisionBetween(1, 100000, true, 'blockedLayer');

The first two parameters specify a range of tile ids. When you save a map in Tiled, a unique id is specified for each different tile. If you open level1.json you’ll see these numbers. setCollisionBetween allows you to specify collision for all id’s within a range. By specifying between 1 and a really large number like 100000 I’m making sure collision is on for all tiles in the blockedLayer, which is what I want in this case.

We are resizing the game world to the size of the background layer. It could have been the blocked layer too as they are the same size, it doesn’t matter.

For now we’ll ignore step 8 of the list (creating objects from the objects layer).

Executing this should show you both layers on your browser. Now it’s time to give some life to the player!

Adding the player

Our player is on the screen already, but not doing much! We want to give it gravity so that it’s not just floating around like a fool.

For that, we need to enable physics on it. Once physics is enabled, the player sprite will have a property called body, which will have all the physics properties and behavior.

//create player
 
this.player = this.game.add.sprite(100, 300, 'player');
 
//enable physics on the player
 
this.game.physics.arcade.enable(this.player);
 
//player gravity
 
this.player.body.gravity.y = 1000;
 
//the camera will follow the player in the world
 
this.game.camera.follow(this.player);

We’ve not only given the player a physical body, but gravity too! now the player should fall go through the ground, and the camera should follow the player through out the level. Let’s make it so that the player hits the ground instead of going through.

Collision detection

Collision detection means we detect when two game elements intersect each other and can carry out actions accordingly.

Phaser gives us two options: collide and overlap. If we specify a collide method between two objects, they will reach physically to the crash, for example their velocity will stop. If we specify an overlapping behavior on the other hand, they don’t affect each other, it’s as if you touched an hologram.

In our game we want to have collision between the player and the floor, and we want to have an overlapping behavior between the player and the coins (otherwise when you touch a coin it will be as if you hit a wall!).

The update method is the place to take care of collision detection, as it gets triggered on every game tick (“multiple times per second”).

Something tricky that can happen in your game if you have bad performance: if the performance is too low, if could happen that collision detection doesn’t take place on time and your place goes through walls and floor. So keep an eye on the fps!!

Lets add the following to update():

//collision
 
this.game.physics.arcade.collide(this.player, this.blockedLayer, this.playerHit, null, this);

We add then a playerHit method in our Game state. This method will be executed when the player collides with the blockedLayer. For now, it will be empty.

playerHit: function(player, blockedLayer) {}

If we were not to add code here later, you could have just done:

this.game.physics.arcade.collide(this.player, this.blockedLayer)

Our player should now hit the ground.

Basic side-scrolling

Now we’ll give our player a velocity in x so that it moves to the right, and we’ll add the ability to jump using the UP key.

In Phaser and all HTML5 game frameworks that I’m aware of, the X axis increases to the right and decreases to the left. The Y axis increases when you go down and decreases when you go up. The origin of the coordinate system is on the top-left corner.

In Phaser and all HTML5 game frameworks that I’m aware of, the X axis increases to the right and decreases to the left. The Y axis increases when you go down and decreases when you go up. The origin of the coordinate system is on the top-left corner.

At the end of the create method initiate the cursor keys (the arrow keys):

[javscript]//move player with cursor keys
 
this.cursors = this.game.input.keyboard.createCursorKeys();[/javascript]

In the update method, add:

this.player.body.velocity.x = 300; 
 
if(this.cursors.up.isDown) {
 
    this.playerJump();
 
}

The first thing we are doing is give the player a velocity on x of 300. We can do this since we enabled the physics engine for the player (otherwise it wouldn’t have a body).

If the UP arrow is pressed, we run a method called playerJump. Let’s add this method in the Game state:

playerJump: function() {
 
    if(this.player.body.blocked.down) {
 
      this.player.body.velocity.y -= 700;
 
    }   
 
  },

We are checking whether the player is touching the ground or not. If it is then we can jump. The jump consists of setting a velocity on Y (negative as we are going up).

Now you should be able to have your character move on the level and jump some obstacles. We still can’t duck but will be adding that next.

Ducking

Besides jumping, we also want to be able to duck and avoid obstacles. We’ll follow a similar approach to that of the jumping. The only difference is that we want to change the sprite image for when the player ducks to the image “player_duck.png” (key “playerDuck” in Preload).

In the create method, after setting the player gravity, we’ll add:

//properties when the player is ducked and standing, so we can use in update()
 
var playerDuckImg = this.game.cache.getImage('playerDuck');
 
this.player.duckedDimensions = {width: playerDuckImg.width, height: playerDuckImg.height};
 
this.player.standDimensions = {width: this.player.width, height: this.player.height};
 
this.player.anchor.setTo(0.5, 1);

Before going through each line of code let me explain what we are doing. When the player ducks we want to change the image to “playerDuck”. Changing the image is one thing, but we also have to update the body of our player which represents the physics object. Even if we change the image to a smaller image, the body will not change unless we explicitly tell it to.

Moreover, after we duck we want the player to stand up again and therefore we have to update the body of the player one more time.

The first line, what it does is grab the playerDuck image so that we can read it’s dimensions:

var playerDuckImg = this.game.cache.getImage('playerDuck');

Then we save the dimensions of this image, and for the standing player too, in objects that we can tap into later:

this.player.duckedDimensions = {width: playerDuckImg.width, height: playerDuckImg.height};
 
this.player.standDimensions = {width: this.player.width, height: this.player.height};

When the player shrinks the feet should stay on the floor, that’s how it works when you duck (get up and try it!), so we need to set the anchor point to the bottom of the sprite:

this.player.anchor.setTo(0.5, 1);

Now in the update method we’ll read for the DOWN arrow and make the player duck. Also, if the player is ducked and we are no longer holding the DOWN key, we want the guy to stand up again:

this.player.body.velocity.x = 300; 
 
      if(this.cursors.up.isDown) {
 
        this.playerJump();
 
      }
 
      else if(this.cursors.down.isDown) {
 
        this.playerDuck();
 
      }
 
      if(!this.cursors.down.isDown && this.player.isDucked) {
 
        //change image and update the body size for the physics engine
 
        this.player.loadTexture('player');
 
        this.player.body.setSize(this.player.standDimensions.width, this.player.standDimensions.height);
 
        this.player.isDucked = false;
 
      }

And the playerDuck method:

playerDuck: function() {
 
      //change image and update the body size for the physics engine
 
      this.player.loadTexture('playerDuck');
 
      this.player.body.setSize(this.player.duckedDimensions.width, this.player.duckedDimensions.height);
 
      //we use this to keep track whether it's ducked or not
 
      this.player.isDucked = true;
 
  },

Now you can duck and avoid objects in this way!

Game over

In this game you lose if you fall from a cliff, or if you hit a wall/obstacle instead of avoiding it. To implement the death by falling we’ll add a new check in our update method. If the player’s position is greater or equal than the edge of the game world, then we execute a gameOver() method that will restart the game:

//restart the game if reaching the edge
 
if(this.player.x >= this.game.world.width) {
 
    this.game.state.start('Game');
 
}

The other way the player can die is when hitting an obstacle. Basically, when there is a collision between the player and the blocked layer on the player’s right side. This is because the player is moving to the right. We’ll implement this logic in our playerHit method created previously, which will look like so:

playerHit: function(player, blockedLayer) {
 
    //if hits on the right side, die
 
    if(player.body.blocked.right) {
 
      //set to dead (this doesn't affect rendering)
 
      this.player.alive = false;
 
      //stop moving to the right
 
      this.player.body.velocity.x = 0;
 
      //change sprite image
 
      this.player.loadTexture('playerDead');
 
      //go to gameover after a few miliseconds
 
      this.game.time.events.add(1500, this.gameOver, this);
 
    }
 
  },

See how we are checking for a property “alive”. This property is present in all sprites in Phaser, it doesn’t affect rendering but it’s been placed there for our convenience, as having game elements live or die is common to most games.

When the player hits on the right side (player.body.blocked.right), we stop the movement, set the player to “not alive”, change the image to the playerDead image that we loaded in Preloaded, and restart the game after 1.5 seconds (just so you can give it time to hit the floor!).

But hey, even if the player is dead we are still able to make it jump or duck if you use the keys. We need to check whether the player is alive before making it jump or duck. Let’s modify update, it will look like this now:

update: function() {
 
    //collision
 
    this.game.physics.arcade.collide(this.player, this.blockedLayer, this.playerHit, null, this);
 
    this.game.physics.arcade.overlap(this.player, this.coins, this.collect, null, this);
 
    //only respond to keys and keep the speed if the player is alive
 
    if(this.player.alive) {
 
      this.player.body.velocity.x = 300; 
 
      if(this.cursors.up.isDown) {
 
        this.playerJump();
 
      }
 
      else if(this.cursors.down.isDown) {
 
        this.playerDuck();
 
      }
 
      if(!this.cursors.down.isDown && this.player.isDucked) {
 
        //change image and update the body size for the physics engine
 
        this.player.loadTexture('player');
 
        this.player.body.setSize(this.player.standDimensions.width, this.player.standDimensions.height);
 
        this.player.isDucked = false;
 
      }
 
      //restart the game if reaching the edge
 
      if(this.player.x >= this.game.world.width) {
 
        this.game.state.start('Game');
 
      }
 
    }
 
  },

Loading objects from a Tiled object layer

So far we’ve only loaded the tile layers from our Tiled map. Don’t forget we also created an objects layer. In order to load these objects you can use the methods that come with theTilemap class, but if you do then you have to create an objects layer for each type of object you want to have (and for each sprite image they will have as well).

Another option which I prefer is to use a single objects layer for all the objects in the game, and specify in each individual object the type of object it will be, and the sprite image it will use. For us to do that I’ve created two helper methods that we’ll add to the Game state.

The first method findObjectsByType will allow us to get an array with all the objects from the objects layer that match a certain type (remember how we specified the type when we created our objects layer in Tiled):

//find objects in a Tiled layer that containt a property called "type" equal to a certain value
 
  findObjectsByType: function(type, map, layerName) {
 
    var result = new Array();
 
    map.objects[layerName].forEach(function(element){
 
      if(element.properties.type === type) {
 
        //Phaser uses top left, Tiled bottom left so we have to adjust
 
        //also keep in mind that some images could be of different size as the tile size
 
        //so they might not be placed in the exact position as in Tiled
 
        element.y -= map.tileHeight;
 
        result.push(element);
 
      }     
 
    });
 
    return result;
 
  },

The second method createFromTiledObject we’ll use is to create a sprite from an object. So for example, we use the first method to grab all the “coins”, then we use the second method to actually create a sprite for them.

//create a sprite from an object
 
  createFromTiledObject: function(element, group) {
 
    var sprite = group.create(element.x, element.y, element.properties.sprite);
 
      //copy all properties to the sprite
 
      Object.keys(element.properties).forEach(function(key){
 
        sprite[key] = element.properties[key];
 
      });
 
  },

Loading coins

By using the two helper methods we’ll create all the coins in the game. In the create method, add the following after the world resizing statement:

this.createCoins();
 
Let's implement the createCoins method:
 
//create coins
 
  createCoins: function() {
 
    this.coins = this.game.add.group();
 
    this.coins.enableBody = true;
 
    var result = this.findObjectsByType('coin', this.map, 'objectsLayer');
 
    result.forEach(function(element){
 
      this.createFromTiledObject(element, this.coins);
 
    }, this);
 
  },

What’s going on here:

  1. We create a new group of sprites called coins. In Phaser you use groups to easily work with sets of elements that have the same/similar properties and behaviors. For example you’d create groups for enemies, collectables, items,etc.
  2. We enable the physics system for the whole group.
  3. We find all the coin objects from the objectsLayer.
  4. What we got there was an array of objects. Now we want to create an actual sprite for each one of these objects.

We want the player to collect the coins. When the player touches a coin, the velocity of the player shouldn’t be affected (or that of the coin), so we use an overlap type of checking instead of collide. In the update method:

this.game.physics.arcade.overlap(this.player, this.coins, this.collect, null, this);

We’ll implement the collect method next.

Sound

Playing sounds in Phaser is very straightforward and follows the same approach of loading/using other assets. We have to load them first in Preloader:

this.load.audio('coin', 'assets/audio/coin.wav');

Then we create the audio object in our create method in the Game state:

//sounds
 
this.coinSound = this.game.add.audio('coin');

To play a sound you just use the play() method of the sound object. We play the coin sound on the collect method (when the user grabs the coins):

collect: function(player, collectable) {
 
    //play audio
 
    this.coinSound.play();
 
    //remove sprite
 
    collectable.destroy();
 
  },

Ideally you’d want to keep track of the coins and show the total on the screen, but for this example I’m omitting that part. If you want to see this done check my other tutorial HTML5 Game Development with Phaser – SpaceHipster a Space Exploration Game.

Extra notes regarding sound

  • Phaser uses the WebAudio API if available, otherwise it represents the sounds using AUDIO tags. This is handled for your automatically.
  • Different browsers have different support for audio formats. In Phaser you can pass on multiple audio files for the same audio, so that the engine will play the correct format for the browser. See this discussion.
  • Try to compress your audio files as much as possible. You can do so using Audacity, a free sound utility. I usually decrease the project rate (HZ) as much as possible while the quality is good. Then you export the file as OGG and MP3.

Touch controller

In this section we’ll add a touch controller using an external library called HTML5 Virtual Game Controller. Checkout their page to see screenshots and code examples for different types of controllers.

In our game we just want two buttons. One for jumping and one for ducking. If I was to publish this game I’d prefer to just swipe or touch the screen for these actions, but I really wanted to include a touch controller usage in this tutorial so here we go.

The first thing we did was include gamecontroller.js (or gamecontroller.min.js) in our index page. This creates a global object called GameController.

This controller gets drawn on the CANVAS. We only want to draw it once as otherwise every time we restart the state it gets re-drawn. In our create method in the Game state add:

//init game controller
 
this.initGameController();
 
Lets implement this method:
 
initGameController: function() {
 
    if(!GameController.hasInitiated) {
 
      var that = this;     
 
      GameController.init({
 
          left: {
 
              type: 'none',
 
          },
 
          right: {
 
              type: 'buttons',
 
              buttons: [
 
                false,
 
                {
 
                  label: 'J',
 
                  touchStart: function() {
 
                    if(!that.player.alive) {
 
                      return;
 
                    }
 
                    that.playerJump();
 
                  }
 
                },
 
                false,
 
                {
 
                  label: 'D',
 
                  touchStart: function() {
 
                    if(!that.player.alive) {
 
                      return;
 
                    }
 
                    that.pressingDown = true; that.playerDuck();
 
                  },
 
                  touchEnd: function(){
 
                    that.pressingDown = false;
 
                  }
 
                }
 
              ]
 
          },
 
      });
 
      GameController.hasInitiated = true;
 
    }
 
  },

GameController.hasInitiated is a variable we’ll use to keep track whether the controller has been initiated so we don’t do it twice.

See how we are checking for player.alive and working in a similar way than what we did with the keyboard.

One thing we want to change in update, is that if the down key is not being pressed but the duck button is being pressed, we don’t want the player to stand up, so replace the following:

//instead of: if(!this.cursors.down.isDown && this.player.isDucked) {
 
if(!this.cursors.down.isDown && this.player.isDucked && !this.pressingDown) {

And there you go! on-screen touch controller for the mobile :)

Where to go next

We’ve come a long way with a simple playable demo!

In case you haven’t already, have a look a the complete source code and you can also play the game here.

There is much more to Phaser for you to explore! make sure you know your way around theexamples and documentation, and become an active member of the community.

If you want a deeper and much more advanced training on the framework and HTML5 gamedev in general you can check our online course HTML5 Mobile Game Development with Phaser, which covers the creation of a game similar to Jetpack Joyride, including advanced mechanics, animations, spritesheets and tips on how to make your games juicy.

Feel free to leave feedback and comments!

You can also reach me on my site ZENVA.com

Thanks for reading.

For more complete information about compiler optimizations, see our Optimization Notice.