How to create fun and interactive JavaScript games using Phaser.io

phaser-logo.pngPhaser.io is a HTML5 game framework that gives you all the necessary tools to create a game in JavaScript. It’s easy to setup and also easy to learn with a lot of quality documentation and example code snippets available online. It works in all modern browsers using WebGL (for the browsers that support WebGL) or Canvas for rendering.

 

Why Phaser?

We made basic JavaScript games for our customers before but the game ideas became more complex and required a lot more coding. Basic JavaScript + canvas code became unnecessarily complex and harder to maintain. So we started looking for a framework that would help us create those same games faster and far more constructive than before

This blogpost will show some of the basic Phaser features, which we already used in some of our online games. But take note: when reaching the end of this blogpost, we'll only have seen the tip of the iceberg of all Phaser has to offer.

 

why_phaser.png

 

Requirements

What we need to get started is, first of all, a webbrowser that supports the <canvas> html tag, being (official support list):

  • For desktop: IE9+, Firefox, Chrome, Safari and Opera
  • For mobile: iOS Safari, Android browser and Chrome

You can use Phaser.io in either JavaScript or TypeScript. All our examples will be in JavaScript.

Lastly, but probably the most important part of a good game: A fun and addictive game idea with some good looking visuals!

 

Setup

Initialize the game canvas/world:


var game = new Phaser.Game(800, 600, Phaser.AUTO, 'game', {
    preload: preload,
    create: create,
    update: update,
    render: render
});

  • 800: canvas width
  • 600: canvas height
  • AUTO: Renderer (Canvas or WebGL), AUTO lets phaser decide what is best for our web browser
  • ‘game’: Parent or canvas element
  • Phaser state functions
    • preload: In this function, we will preload all the things we need, like images, spritesheets, json files, …
    • create: In this function, we configure some basic settings and we will create our objects in the game world
    • update: This function runs everytime the gameworld updates (x times / second)
    • render: This function runs on render and is only used for debugging(!!!)

 

Images, spritesheets and tweens

You first need to load the image or spritesheet in the preload() function. After that, we can create a sprite object in the create() function, using the images we preloaded.

icon_phaser.pngicon_phaser1.png


function preload() {
    game.load.image('character', '/assets/character.png');
    game.load.image('enemy', '/assets/enemy.png');
}

var background;
var character;
function create() {
    // Character
    character = game.add.sprite(game.width/2, game.height/2, 'character');
    character.anchor.set(0.5, 0.5);

    // Enemy
    enemy = game.add.sprite((game.width/2) - 100, game.height/2, 'enemy');
    enemy.anchor.set(0.5, 0.5);
}

Phaser_spritesheet.pngThese are static images, but we can also add spritesheets with their own animation. When preloading a spritesheet, we pass the frameWidth, frameHeight and number of frames. Because we want the spritesheet to “play”, we add an animation. When triggering this animation, we pass the animation name, frames per second, loop on true, killOncomplete on false.


function preload() {
    …

    game.load.spritesheet('explosion', '/assets/explosion.png', 64, 64, 25);
}

var explosion;
function create() {
    …
    
    // Explosion
    explosion = game.add.sprite((game.width/2) - 200, game.height/2, 'explosion');
    explosion.animations.add('explode');
    explosion.animations.play('explode',30, true, false);
}

Our objects are still pretty static (apart from the spritesheet, which is animated). We also want the objects to move around in the world. We can use tweens for that. Tweens alter properties of an object over a specific amount of time/duration.

As an example, we want our enemy to move back and forth between and to specific positions. We alter its Y-coordinate over a specific amount of time. (We simply add this in the create() function, after we initiated the sprite object)


game.add.tween(enemy).to({ y: 10}, 2000, Phaser.Easing.Linear.InOut, true, null, false, true);

  • { y: 10}: the Y-coordinate we want at the end of the tween
  • 2000: the amount of time (duration)
  • Easing.Linear.InOut: an easing algorithm effect (http://gamemechanicexplorer.com/#easing-1)
  • True: autoStart
  • Null: delay
  • False: amount of time we want the tween to repeat itself, false makes it repeat continuously
  • True: creates the yoyo effect (back and forth)

 

Input control

Tweens help us move objects around automatically. But we can also control the movement of our objects using our mouse cursor or the arrows on our keyboard. For the example below, we will move our character object by altering the X/Y-coordinates when our UP/DOWN/RIGHT/LEFT key is down.


var speed = 4;
function update() {
    // Character keyboard movement
    if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) {
        character.x += speed;
    } else if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) {
        character.x -= speed;
    } else if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) {
        character.y -= speed;
    } else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) {
        character.y += speed;
    }
}

Game Physics

This is where things get really interesting, but also a bit more complicated. There are 3 main physics engines in Phaser:

  • Arcade: Bounded rectangles, without rotation. This basically means that, for collision etc, we draw a rectangle around our sprite and that will be our bounding box.
    Fast, cheap and easy to use!
  • Ninja: Bounded rectangles with rotation. This is basically Arcade, but with the main difference that we can rotate our rectangles and place them in an angle. For example, if we want to create an up or down slope in our game level.
  • P2: Full-body physics with contraints, polygon support and more. This is the most advanced physics engine and is used for the more advanced/gravity-like games such as Angry Birds.

As the use case of physics is very big and variated, I recommend you to just explore the huge library of examples, which can be found on the phaser.io website:

 

Collision detection

I’ll be using Arcade physics for the next example, but we can also apply this in the other physics engines.

For a lot of games we want to trigger events when a certain sprite hits or overlaps with another sprite. For this, we can check for a collision between two sprites or an overlap between two sprites. I commonly use overlap, because for collision detection one of the two objects needs to be static. Otherwise it will not collide, it will overlap.

In the following example, we add overlap check in the update function. When character and enemy collide, we call the collisionhandler() function, which will log a message in our dev console and will reset the position of our character to the middle of the screen.


function update() {
    …

    // Collision detection
    game.physics.arcade.overlap(character, enemy, collisionHandler);
}

function collisionHandler(obj1, obj2) {
    console.log('collision!!!');
    obj1.x = game.width / 2;
    obj1.y = game.height / 2;
}

Using objects and groups 

What if we don’t have 1 enemy, but A LOT of them? In that case, we can create an enemy group, and, instead of applying overlap detection to a single enemy, we just apply it to the group. This enables all our enemies to trigger the overlap with our character.


var enemyGroup;
function create() {
    …

    // Enemies
    enemyGroup = game.add.group();
    game.time.events.loop(250, function(){
        var enemy = new Enemy(game.world.randomX, game.world.randomY, 'enemy');
        enemyGroup.add(enemy);
    });
}

function update() {
    …

    // Collision detection
    game.physics.arcade.overlap(character, enemyGroup, collisionHandler, null, this);
}

There are a few things you’ll notice in the create function. First of all: the time.events.loop, which is a setInterval in Phaser, and the fact that I’m initiating my enemy using an Object. This will help us set equal properties for all enemies. And we can also create our specific update() function (as we have for the whole game) for these enemy objects.

 


Enemy = function (posX, posY, sprite) {
    Phaser.Sprite.call(this, game, posX, posY, sprite);
    this.outOfBoundsKill = true;
    this.collisionEnabled = false;
    game.physics.arcade.enable(this, true);
}

Enemy.prototype = Object.create(Phaser.Sprite.prototype);
Enemy.prototype.constructor = Enemy;
Enemy.prototype.update = function () {
   // do update stuff for our enemy
}

Summary 

So, as I said in the beginning of the blogpost, this is just the tip of the iceberg. But with all these things combined, you should be able to setup a small interactive mini game.

Some example games created with Phaser: Held van de PMD, Essent Buzzwire,...

I strongly recommend having a look at the official Phaser tutorials, documentation and mainly their examples page. It has many examples for the many different features of Phaser. All source code is available and free to use. http://phaser.io/examples

Some other resources that I found helpful:

Meer weten? Contacteer ons!