Phaser 2.0 Tutorial: Flappy Bird (Part 2)

Intro to Physics and Prefabs

My new video tutorial series HTML5 Mobile Game Development with Phaser over at ZenvaAcademy has just gone live.

While reading a blog might be great, watching someone actually create a game in front of you is a lot more engaging and you really get a feel for what goes into making a simple game.

Read the announcement post

In Part 1, we discussed how to get a game up and running with a menu system using Phaser, basic asset loading, and sprites. In Part 2, we're going to discuss implementing a physics system and introduce Prefabs.

What is a Prefab?

Prefab literally means "pre-fabricated".

In our case, a prefab is a game object that has been setup so that it can be instantiated multiple times and have the same basic properties each time. Technically speaking, it's simply a term in game-development for classes/prototypes that reference a game object with predefined visuals and behaviours.

Pop open your editor and open up the play.js game state file and remove all of the code from the create() and update() functions so that your file looks like the following:

  'use strict';
  function Play() {}
  Play.prototype = {
    create: function() {
    },
    update: function() {
  };

  module.exports = Play;

Let's also edit the preload.js file so that we are taken directly to the play state, so that we don't have to go through the menu each time we want to see progress. Currently the update() function in preload.js looks like this:

update: function() {  
      if(!!this.ready) {
        this.game.state.start('menu');
      }
    }

Change it to look like the following:

update: function() {  
      if(!!this.ready) {
        this.game.state.start('play');
      }
    }

Now that we've got a clean state, let's do the single most important thing that's now required by the game.

Enabling Physics

We're going to use Phaser's Arcade physics engine in our game due to it's simplicity.

Jump back over to play.js and at the top of your create() function, add the following line:

create: function() {  
    this.game.physics.startSystem(Phaser.Physics.ARCADE);
}

This tells Phaser that we're going to use the Arcade physics system. When Phaser hits this line, it does a whole bunch of internal magic, not the least of which is tell our game to begin running physics simulation on every frame.

Setting Gravity

Setting global gravity for the game is ridiculously easy. The following example shows how to do that.

create: function() {  
    this.game.physics.startSystem(Phaser.Physics.ARCADE);
    this.game.physics.arcade.gravity.y = 500;
}

Now, every sprite added to the game with a physics body will accelerate towards the ground at a maximum rate of 500 pixels per second.

We'll actually be pulling this code back out later, as we have some special circumstances to consider, but for now, let's go ahead and leave it in.

Add the background

This works -exactly- like it did in Part 1.

create: function() {  
    /* physics and gravity code gere */

    // add the background sprite
    this.background = this.game.add.sprite(0,0,'background');
}

Upon browser refresh, you will be greeted with a screen that simply has our background image on it. Notice that, even though we have physics and gravity enabled, the background doesn't fall. That's because the background doesn't have physics enabled on it.

Generating a Prefab

On to the fun part.

We're gonna create a Bird prefab that will contain all of the behaviours and code that dictates the way our bird moves. Jump over to your terminal that's currently working in your game directory and run the following command:

$ yo phaser-official:prefab "bird"

There will be some prompts that ask for input, use the following:

$ yo phaser-official:prefab bird
Creating the new prefab: bird  
[?] What is the name of your prefab? bird
[?] What sprite key would you like to use? bird
   create game/prefabs/bird.js

bird will be the name of our prefab, and we're also going to use the 'bird' sprite key that we already loaded.

If you don't already have grunt running, go ahead and do that now.

You should see a new file under game/prefabs/ called 'bird.js'. Open it up and you should see this:

'use strict';

var Bird = function(game, x, y, frame) {  
  Phaser.Sprite.call(this, game, x, y, 'bird', frame);

  // initialize your prefab here

};

Bird.prototype = Object.create(Phaser.Sprite.prototype);  
Bird.prototype.constructor = Bird;

Bird.prototype.update = function() {

  // write your prefab's specific update code here

};

module.exports = Bird;  

The generator has automatically created this class file, which automatically inherits from Phaser.Sprite, and will automatically build it into game.js when the build runs.

Customizing a prefab

We're going to write some code in bird.js that will should look familiar from Part 1.

var Bird = function(game, x, y, frame) {  
  // The super call to Phaser.Sprite
  Phaser.Sprite.call(this, game, x, y, 'bird', frame);

  // set the sprite's anchor to the center
  this.anchor.setTo(0.5, 0.5);

  // add and play animations
  this.animations.add('flap');
  this.animations.play('flap', 12, true);
}

In Part 1, We setup animations on our bird like this:

this.bird = this.add.sprite(200,5,'bird');  
this.bird.animations.add('flap');      this.bird.animations.play('flap', 12, true);  

However, our prefab is now a class, and the this keyword now references the current instantiation. Therefore, any operation or property that we would have set or called on this.bird in the menu, is now done via this in our new Sprite prefab.

Adding a physics body to a sprite

Now, comes the second most important thing we can do in a physics based game. We'll add a physics body to our Bird prefab:

var Bird = function(game, x, y, frame) {  
    /* super and animations setup here */
    this.game.physics.arcade.enableBody(this);
}

That's it, that's all we have to do to have our game recognize this sprite as having physics.

Now, let's put it on the screen in play.js

Requiring Prefabs and other modules

Because we're using browserify to enable the use of the node module pattern, whenever we create a new prefab or other class file that we want to use in other parts of the game, we'll need to make a request to a globally available method that browserify adds called require().

A requirey statement looks like this:

var ClassName = require('relative/path/to/file');  

This will find a file in the path and import it's module.exports value and set it to ClassName.

In this case, in play.js just below the 'use strict'; statement, add the following:

var Bird = require('../prefabs/bird');  

What we're doing here is stepping back one directory (../) and then stepping forward into the prefabs/ directory and the module that's defined in bird.js.

Now the Bird class is available to us to use anywhere inside of play.js;

Adding a prefab instance to the state

Now that we've required our prefab class, we can instantiate it normally in our create() function like so:

create: function() {  
    /* physics and background instantiation here */

    // Create a new bird object
    this.bird = new Bird(this.game, 100, this.game.height/2);
    // and add it to the game
    this.game.add.existing(this.bird);
}

When you check your browser, you should see this:
bird-physics

We've now got the single most important part of the game working. Physics.

But, we need something for our bird to collide into so that she doesn't fall out of the world

The true power of prefabs

In our game, we will only have one bird player at a time, so using a prefab to create our bird might seem like over engineering. But, as a thought experiment, let's take a look at what creating a prefab actually does for us.

Let's say you wanted to create 10 birds at random places on the screen. Without a prefab, your code might look like this:

create: function() {  
    this.game.physics.startSystem(Phaser.Physics.Arcade);

    var birdGroup = this.game.add.group();
    for(var i = 0; i < 10; i++) {
        var bird = new Bird(this.game, this.game.world.randomX, this.game.world.randomY);
        bird.anchor.setTo(0.5, 0.5);
        bird.animations.add('flap');
        bird.animations.play('flap', 12, true);
        this.game.physics.arcade.enableBody(bird);
        this.game.add.existing(bird);
        birdGroup.add(bird);
    }

But with a prefab:

create: function() {  
    this.game.physics.startSystem(Phaser.Physics.Arcade);

    var birdGroup = this.game.add.group();
      for (var i = 0; i < 10; i++) {
        var bird = new Bird(this.game, this.game.world.randomX, this.game.world.randomY);
        birdGroup.add(bird);
      }
}

Either way, you'll end up with this:
multiple-birds

With both methods, each bird in the birdGroup has the same properties and physics. However, the second example is cleaner and, when we add methods to our bird class, is really the only way we can control all of the birds.

Ok, back to the real world...

Creating a TileSprite prefab

We're going to add a ground TileSprite (much like in Part 1), but this time, we're going to do with with a prefab.

Jump back to your terminal and run the following command:

$ yo phaser-official:prefab "ground"

and answer the prompts like so

reating the new prefab: ground  
[?] What is the name of your prefab? ground
[?] What sprite key would you like to use? ground
   create game/prefabs/ground.js

Open up ground.js in the game/prefabs/ directory. It should look -exactly- like bird.js did before we started modifying the code, with the exception that the class should be called Ground.

Looking at the code in ground.js, you might be saying "I thought you said we were going to use a TileSprite, instead of a Sprite, which is what the class is inheriting from."

And you'd be right. Here's a cookie for catching that.

Luckily for us, javascript is so malleable, that it's a menial task to have our prefab inherit from TileSprite instead of Sprite. Modify ground.js to look like the following:

'use strict';

var Ground = function(game, x, y, width, height) {  
  Phaser.TileSprite.call(this, game, x, y, width, height, 'ground');
};

Ground.prototype = Object.create(Phaser.TileSprite.prototype);  
Ground.prototype.constructor = Ground;

Ground.prototype.update = function() {  
  // write your prefab's specific update code here  
};

Now, our Ground prefab is inheriting from from Phaser.TileSprite instead of Phaser.Sprite

Adding physics to our ground

Why Add Physics to our Ground Prefab?

Because anything that needs to collide with anything else must have a physics body.

This works in exactly the same way as adding physics to our bird

var Ground = function(this.game, x, y, width, height) {  
  Phaser.TileSprite.call(this, this.game, x, y, width, height, 'ground', frame);

  // enable physics on the ground sprite
  // this is needed for collision detection
  this.game.physics.arcade.enableBody(this);
}

Now, any time you create a new Ground object, it will automatically have physics, just like our Bird prefab.

Let's add a ground to our play state:

create: function() {  
    /** All previous code **//

    // create and add a new Ground object
    this.ground = new Ground(this.game, 0, 400, 335, 112);
    this.game.add.existing(this.ground);
}

Remember, because we inherited Ground from TileSprite, we need to pass in the required TileSprite parameters, which are (game, x, y, width, height, key). Because we've hardcoded the key in the class to be 'ground' we don't have to pass that in.

Go ahead and check your work.
ground-physics-1 Uh, Oh

There's a few problems here. First, and most noticibly, is the fact that our ground now reacts to gravity just like our bird, which causes it to fall away. It also doesn't scroll like the ground in the menu. Let's fix both of these

var Ground = function(this.game, x, y, width, height) {  
  Phaser.TileSprite.call(this, this.game, x, y, width, height, 'ground');
  // start scrolling our ground
  this.autoScroll(-200,0);

  // enable physics on the ground sprite
  // this is needed for collision detection
  this.game.physics.arcade.enableBody(this);

  // we don't want the ground's body
  // to be affected by gravity
  this.body.allowGravity = false;
};

You'll recognize the autoScroll method from Part 1. The second part, however, is the piece that we need to keep our ground from giving way to gravity.

What is this.body?

this.body is a reference to a GameObject's physics body. It's a very complicated object that contains physics data and determines how an attached object moves, collides, and behaves in a given physics simulation. Each physics system's body object has different methods for manipulation and collision.

this.body.allowGravity is a simple switch for telling the Arcade physics system whether or not to allow this body to be affected by gravity.

Let's check our work:
ground-physics-2

Excellent, our ground is staying... on the ground. But our bird just falls right on through.

Making Things Collide

We've got our bird and our ground. Now, let's make them collide.

Open up play.js, scroll down to the update() function, and add the following code:

update: function() {  
    this.game.physics.arcade.collide(this.bird, this.ground);
}

This single line of code tells the Arcade physics system to check collisions between this.bird and this.ground. If a collision is detected, the physics system reacts accordingly, and that's why we see this:

ground-physics-3

What the hell is going on?

A valid question. Let's break down everything we've done (with respects to physics) as a human readable statement.

In the create() method of our play state, we told Phaser to use the Arcade physics system. We then setup global gravity so that everything with a physics body would fall and collide properly. In our Bird prefab, we told the physics system to create a body on our sprite which, in effect, told our physics system to apply global physics and collisions to it. We told our physics system basically the same thing in our Ground prefab. However, we told the physics system to make the ground not react to gravity. Then, in the update loop of our play state, we told the physics system to collide our bird and our ground, and to apply any physics simulation that occurs because of it, to said objects.

What we haven't done is told our physics system to have the ground not react to collisions. So, in effect, when our bird and ground collide, Arcade applies forces to our ground inflicted upon it by the bird, which in turn, causes our ground to be pushed downward by the force of the falling bird.

Let's disable that.

In ground.js, just below the line that disallows gravity, we'll add the following line:

this.body.immovable = true;  

This single and simple line of code tells the physics system that any Ground object created should only react to physics created and set by itself, and not from external forces.

We should now be seeing the following on screen:
ground-physics-4

Want More?

My new video tutorial series HTML5 Mobile Game Development with Phaser over at ZenvaAcademy has just gone live.

While reading a blog might be great, watching someone actually create a game in front of you is a lot more engaging and you really get a feel for what goes into making a simple game.

Read the announcement post


Next Time:

In Part 3 of this tutorial series, we'll be looking at player controls and animation.

Source Code

All relevant code from this lesson is available in gist form here: Phaser 2.0 Tutorial: Flappy Bird (Part 2)