Phaser.js tutorial: Building a polished space shooter game (Part 1)

Phaserfire game screenshot

This is a javascript game tutorial for a presentation I gave using the phaser.js HTML5 game engine. We will be building a classic vertical scrolling space shooter game, and will focus on polish and production value.

The tutorial is broken down step-by-step in chronological development order, and separated into five general themes:

You can play the finished game here. All of the code and assets are available on github. In the code below, new code is in green, and removed code is in red.

In this first part, we will cover the basics of setting up a phaser.js game, create a setting, and the ship that the player controls. We’ll do a few iterations on the math and physics that control the ship, to improve how it moves and feels. We also add some effects to the ship to make it feel more responsive and alive, and improve the overall production value.

The internet has many tutorials on building games with phaser, and the phaser docs and examples are excellent, so instead of walking you through the api and implementation details, this tutorial will focus on the execution of creating a game that feels alive, responsive, and polished, with high production value.

In the steps below, new code in each step is shown in green, and removed code is in red.

Step 1: Load phaser game and add a background and ship

All phaser states have the preload, create, update, and render methods. We load those four methods directly into a new game (our game will only make use of a single “game state”).

We need an object to control, and a setting, so we preload a space ship and star field asset, then we create them both as sprites.

Play the game at this step
View the code at this step


+var game = new Phaser.Game(800,600, Phaser.AUTO, 'phaser-demo', {preload: preload, create: create, update: update, render: render});
+
+var player;
+var starfield;
+
+function preload() {
+    game.load.image('starfield', '/assets/starfield.png');
+    game.load.image('ship', '/assets/player.png');
+}
+
+function create() {
+    //  The scrolling starfield background
+    starfield = game.add.tileSprite(0, 0, 800, 600, 'starfield');
+
+    //  The hero!
+    player = game.add.sprite(400, 500, 'ship');
+    player.anchor.setTo(0.5, 0.5);
+}
+
+function update() {
+
+}
+
+function render() {
+
+}
+

Step 2: Add movement effect by scrolling the background

To get the simple illusion of movement, we offset the tile position of the background a little every frame.

Play the game at this step
View the code at this step


...
 }
 
 function update() {
+    //  Scroll the background
+    starfield.tilePosition.y += 2;
 
 }

Step 3: Add basic movement to the ship

We’ll use phaser’s automatic cursor key binding for inputs, and wire those up to affect the ship’s x-coordinate velocity. We have to give the ship a physics body to use velocity. The standard arcade physics engine is sufficient for our needs.

Note how the ship moves now – it is either at 100% throttle, or 0%, meaning it goes from 0 px/ms to 200 px/ms instantly, and vice versa. It would be better if it accelerated and decelerated smoothly…

Play the game at this step
View the code at this step


...
 
 var player;
 var starfield;
+var cursors;
 
 function preload() {
     game.load.image('starfield', '/assets/starfield.png');
...
     //  The hero!
     player = game.add.sprite(400, 500, 'ship');
     player.anchor.setTo(0.5, 0.5);
+    game.physics.enable(player, Phaser.Physics.ARCADE);
+
+    //  And some controls to play the game with
+    cursors = game.input.keyboard.createCursorKeys();
 }
 
 function update() {
     //  Scroll the background
     starfield.tilePosition.y += 2;
 
+    //  Reset the player, then check for movement keys
+    player.body.velocity.setTo(0, 0);
+
+    if (cursors.left.isDown)
+    {
+        player.body.velocity.x = -200;
+    }
+    else if (cursors.right.isDown)
+    {
+        player.body.velocity.x = 200;
+    }
 }
 
 function render() {

Step 4: Improve the ship movement feel with acceleration

Instead of binding the movement keys to the ship’s velocity, let’s bind them to its acceleration. We have to give the physics system some more information for it to complete the acceleration calculations.

Now the ship movement has a nice feel – it slowly accelerates, then drifts to a stop. But it still feels quite static…

Play the game at this step
View the code at this step


...
 var starfield;
 var cursors;
 
+var ACCLERATION = 600;
+var DRAG = 400;
+var MAXSPEED = 400;
+
 function preload() {
     game.load.image('starfield', '/assets/starfield.png');
     game.load.image('ship', '/assets/player.png');
...
     player = game.add.sprite(400, 500, 'ship');
     player.anchor.setTo(0.5, 0.5);
     game.physics.enable(player, Phaser.Physics.ARCADE);
+    player.body.maxVelocity.setTo(MAXSPEED, MAXSPEED);
+    player.body.drag.setTo(DRAG, DRAG);
 
     //  And some controls to play the game with
     cursors = game.input.keyboard.createCursorKeys();
...
     starfield.tilePosition.y += 2;
 
     //  Reset the player, then check for movement keys
-    player.body.velocity.setTo(0, 0);
+    player.body.acceleration.x = 0;
 
     if (cursors.left.isDown)
     {
-        player.body.velocity.x = -200;
+        player.body.acceleration.x = -ACCLERATION;
     }
     else if (cursors.right.isDown)
     {
-        player.body.velocity.x = 200;
+        player.body.acceleration.x = ACCLERATION;
     }
 }

Step 5: Add “banking” effect

We can make the ship a little more “juicy” by giving the illusion that it banks and turns in response to our input.

The magic here is simply some well planned math – basically, the closer the ship is to its max velocity, the more it should be rotated and squished to give the illusion of banking.

Now our ship feels very nice!

Play the game at this step
View the code at this step


...
 var player;
 var starfield;
 var cursors;
+var bank;
 
 var ACCLERATION = 600;
 var DRAG = 400;
...
     {
         player.body.acceleration.x = ACCLERATION;
     }
+
+    //  Squish and rotate ship for illusion of "banking"
+    bank = player.body.velocity.x / MAXSPEED;
+    player.scale.x = 1 - Math.abs(bank) / 2;
+    player.angle = bank * 10;
 }
 
 function render() {

Step 6: Stop at screen edges

Just one quick item of business left – our ship can move off-screen, which isn’t desired, so we’ll prevent it.

Play the game at this step
View the code at this step


...
         player.body.acceleration.x = ACCLERATION;
     }
 
+    //  Stop at screen edges
+    if (player.x > game.width - 50) {
+        player.x = game.width - 50;
+        player.body.acceleration.x = 0;
+    }
+    if (player.x < 50) {
+        player.x = 50;
+        player.body.acceleration.x = 0;
+    }
+
     //  Squish and rotate ship for illusion of "banking"
     bank = player.body.velocity.x / MAXSPEED;
     player.scale.x = 1 - Math.abs(bank) / 2;

That’s it for part 1 of this tutorial, thanks for following along!

Next time in part 2, we will look at improving our ship – adding a plasma trail, adding mouse control, and adding the ability to shoot.

If you have any comments or questions, please post them below, and if this tutorial has been useful to you, please share it. See you in part 2.