Introduction
There are dozens of HTML5 game frameworks available out there. However, if you are looking for a free, open source, and actively maintained framework, the list quickly narrows down to just a handful of them. And a lot of people consider Phaser to be the best one.
This tutorial will show you how to make the beginning of a 2D platfromer game in HTML5 using the Phaser framework. This tutorial comes from the beginning of the ebook Discover Phaser.
Grab the Entire Ebook for Much, Much More
Empty Game
Let’s start by creating an empty game. By the end of this part, we will have this:
Don’t worry, it will quickly become more interesting.
Set Up
First we need to create a new directory called “first-game”, where we should add:
- phaser.min.js, the Phaser framework.
- main.js, that will contain the game’s code. For now it’s just an empty file.
- index.html, that will display the game. We can use the same index file that we made in the previous chapter.
- assets/, a directory that contains all the images and sounds. The assets can be downloaded here
Code the Main File
The Javascript code for any new Phaser project is basically always going to be the same:
- Create the states. Remember that a state is a scene of a game, like a loading scene, a menu, etc.
- Initialise Phaser. That’s where we define the size of our game among other things.
- Tell Phaser what the states of our game are.
- And start one of the states, to actually start the game.
These 4 steps are explained below in detail.
First, we create the states. For now we will have only one, that will include 3 of the default Phaser functions:
// We create our only state, called 'mainState' var mainState = { // We define the 3 default Phaser functions preload: function() { // This function will be executed at the beginning // That's where we load the game's assets }, create: function() { // This function is called after the preload function // Here we set up the game, display sprites, etc. }, update: function() { // This function is called 60 times per second // It contains the game's logic }, // And here we will later add some of our own functions };
The preload
, create
and update
functions are key to any Phaser project, so make sure to read the comments above to understand what they do. We will spend most of our time in these 3 functions to create our game.
Then, we initialise Phaser with Phaser.Game
.
Phaser.Game(gameWidth, gameHeight, renderer, htmlElement)
- gameWidth: width of the game in pixels
- gameHeight: height of the game in pixels
- renderer: how to render the game, I recommend using Phaser.AUTO
that will automatically choose the best option between webGL and canvas
- htmlElement: the ID of the HTML element where the game will be displayed
For our game, we add this below the previous code:
// Create a 500px by 340px game in the 'gameDiv' element of the index.html var game = new Phaser.Game(500, 340, Phaser.AUTO, 'gameDiv');
Next, we tell Phaser to add our only state:
// Add the 'mainState' to Phaser, and call it 'main' game.state.add('main', mainState);
And finally, we start our ‘main’ state:
game.state.start('main');
Our empty project is now done. But let’s add a couple of things in it that are going to be useful.
Background Color
By default, the background color of the game is black. We can easily change that by adding this line of code in the create
function:
game.stage.backgroundColor = '#3498db';
The #3498db
is the hexadecimal code for a blue color.
Physics Engine
One of the great features of Phaser is that it has 3 physics engines included. A physics engine is what will manage the collisions and movements of all the objects in the game.
The 3 engines available are:
- P2. It’s a full featured physics system that lets us build games with complex collisions, like Angry Birds.
- Ninja. It’s less powerful than P2, but still has some interesting features to handle tilemaps and slopes.
- Arcade. It’s the most basic system that only deals with rectangle collisions (called AABB), but it also has the best performance.
Which one is the best? It really depends on what type of game we want to build. In our case we will use Arcade physics, and to tell that to Phaser we just need this line of code in the create
function:
game.physics.startSystem(Phaser.Physics.ARCADE);
Conclusion
Once you put all of the Javascript code in the main.js file, you can test the game by using a local webserver.
If you see an empty blue screen, it means that everything is working properly.
Add the Player
The first interesting thing we are going to add to the game is the player, and a way to control it. To do so, we will make some changes to the main.js file.
Load the Player
In Phaser, every time we want to use an asset (image, sound, etc.) we first need to load it. For an image, we can do that with the game.load.image
function.
game.load.image(imageName, imagePath)
- imageName: the new name that will be used to reference the image
- imagePath: the path to the image
To load the player sprite, we add this in the preload
function:
game.load.image('player', 'assets/player.png');
Display the Player
Once the sprite is loaded, we can display it on the screen with game.add.sprite
.
game.add.sprite(positionX, positionY, imageName)
- positionX: horizontal position of the sprite
- positionY: vertical position of the sprite
- imageName: the name of the image, as defined in the preload function
Note that if we add a sprite at the 0, 0 position, it will be displayed in the top left corner of the game.
To add the sprite at the center of the screen we could write this in the create
function:
// Create a local variable var player = game.add.sprite(250, 170, 'player');
However, since we want to be able to use the player everywhere in our state, we need to use the this
keyword:
// Create a state variable this.player = game.add.sprite(250, 170, 'player');
And we can do even better by using some predefined variables for the x and y positions:
this.player = game.add.sprite(game.world.centerX, game.world.centerY, 'player');
That’s the line we should actually add in the create
function.
Anchor Point
If you test the game, you might notice that the player is not exactly centered. That’s because the x
and y
we set in game.add.sprite
is the position of the top left corner of the sprite, also called the anchor point. So it’s the top left corner of the player that is centered, and that’s not what we want.
To fix that, we will need to change the anchor point’s position. Here are some examples of how we can do that:
// Set the anchor point to the top left of the sprite (default value) this.player.anchor.setTo(0, 0); // Set the anchor point to the top right of the sprite this.player.anchor.setTo(1, 0); // Set the anchor point to the bottom left of the sprite this.player.anchor.setTo(0, 1); // Set the anchor point to the bottom right of the sprite this.player.anchor.setTo(1, 1);
To center the player, we need to set the anchor point to the middle of the sprite, in the create
function:
this.player.anchor.setTo(0.5, 0.5);
Add Gravity to the Player
Let’s add some gravity to the player, to make it fall. To do so, we need to add this in the create
function:
// Tell Phaser that the player will use the Arcade physics engine game.physics.arcade.enable(this.player); // Add vertical gravity to the player this.player.body.gravity.y = 500;
Adding Arcade physics to the player is really important, it will allow us to use its body
property to:
- Add gravity to the sprite to make it fall (see above)
- Add velocity to the sprite to be able to move it (see below)
- Add collisions (see in the next part)
Control the Player
There are a couple of things that need to be done if we want to move the player around with the arrow keys.
First, we have to tell Phaser which keys we want to use in our game. For the arrow keys, we simply add this in the create
function:
this.cursor = game.input.keyboard.createCursorKeys();
And thanks to this.cursor
, we can now add a new function (just after the update
) that will handle all the player’s movements:
movePlayer: function() { // If the left arrow key is pressed if (this.cursor.left.isDown) { // Move the player to the left this.player.body.velocity.x = -200; } // If the right arrow key is pressed else if (this.cursor.right.isDown) { // Move the player to the right this.player.body.velocity.x = 200; } // If neither the right or left arrow key is pressed else { // Stop the player this.player.body.velocity.x = 0; } // If the up arrow key is pressed and the player is touching the ground if (this.cursor.up.isDown && this.player.body.touching.down) { // Move the player upward (jump) this.player.body.velocity.y = -320; } },
In Phaser, the velocity is expressed in pixels per second.
And finally, we have to call movePlayer
inside the update
function:
this.movePlayer();
This way, we check 60 times per second if an arrow key is pressed, and move the player accordingly.
Conclusion
As usual, you should check that everything is working as expected. If so, you will be able to control the player while falling, and see him disappear from the screen.
Create the World
Having a player falling is nice, but it would be better if there was a world in which he could move around. That’s what we are going to fix in this part by doing this:
Load the Walls
With 2 sprites (an horizontal and a vertical wall) added at different locations, we will be able to create the whole new world.
As we explained previously, we need to start by loading our assets in the preload
function:
game.load.image('wallV', 'assets/wallVertical.png'); game.load.image('wallH', 'assets/wallHorizontal.png');
You can see that the name of the image doesn’t have to be the same as its filename.
Add the Walls – Idea
Let’s create the left and right walls of the game:
// Create the left wall var leftWall = game.add.sprite(0, 0, 'wallV'); // Add Arcade physics to the wall game.physics.arcade.enable(leftWall); // Set a property to make sure the wall won't move // We don't want to see the wall fall when the player touches it leftWall.body.immovable = true; // Do the same for the right wall var rightWall = game.add.sprite(480, 0, 'wallV'); game.physics.arcade.enable(rightWall); rightWall.body.immovable = true;
That’s 6 lines of code for just 2 walls, so if we do this for the 10 walls it will quickly become messy. To avoid that we can use a Phaser feature called groups, which let us group objects together that can easily share some properties. Here’s how it works for our 2 walls:
// Create a new group this.walls = game.add.group(); // Add Arcade physics to the whole group this.walls.enableBody = true; // Create 2 walls in the group game.add.sprite(0, 0, 'wallV', 0, this.walls); // Left wall game.add.sprite(480, 0, 'wallV', 0, this.walls); // Right wall // Set all the walls to be immovable this.walls.setAll('body.immovable', true);
You may notice that the game.add.sprite
has 2 new optional parameters. It’s the last one that’s interesting to us: the name of the group to add the sprite in.
Add the Walls – Code
Adding walls is not very interesting, all we have to do is to create them at the correct positions. Here’s the full code that does just that, in a new function:
createWorld: function() { // Create our wall group with Arcade physics this.walls = game.add.group(); this.walls.enableBody = true; // Create the 10 walls game.add.sprite(0, 0, 'wallV', 0, this.walls); // Left game.add.sprite(480, 0, 'wallV', 0, this.walls); // Right game.add.sprite(0, 0, 'wallH', 0, this.walls); // Top left game.add.sprite(300, 0, 'wallH', 0, this.walls); // Top right game.add.sprite(0, 320, 'wallH', 0, this.walls); // Bottom left game.add.sprite(300, 320, 'wallH', 0, this.walls); // Bottom right game.add.sprite(-100, 160, 'wallH', 0, this.walls); // Middle left game.add.sprite(400, 160, 'wallH', 0, this.walls); // Middle right var middleTop = game.add.sprite(100, 80, 'wallH', 0, this.walls); middleTop.scale.setTo(1.5, 1); var middleBottom = game.add.sprite(100, 240, 'wallH', 0, this.walls); middleBottom.scale.setTo(1.5, 1); // Set all the walls to be immovable this.walls.setAll('body.immovable', true); },
Note that for the last 2 walls we had to scale up their width with sprite.scale.setTo(1.5, 1)
. The first parameter is the x scale (1.5 = 150%), the second is the y scale (1 = 100% = no change).
And we should not forget to call createWorld
in the create
function:
this.createWorld();
Collisions
If you test the game, you will probably see that there is a problem: the player is going through the walls. We can solve that by adding a single line of code at the beginning of the the update
function:
// Tell Phaser that the player and the walls should collide game.physics.arcade.collide(this.player, this.walls);
This works because we previously enabled Arcade physics for both the player and the walls. However, be careful to always add the collisions at the beginning of the update
function, otherwise it might cause some bugs.
Conclusion
If you test the game, you should be able to jump on the platforms and run around. This is starting to look like a real game, and that’s just the beginning.
Want to learn how to: add enemies, coins, menus, sounds, animations, make the game mobile friendly, and much more? Then you should check out the ebook Discover Phaser.