Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
5. September 2014

 

 

Other than being a word my brain seems to think is spelled incorrectly, Particles are a common part of many games.  Fortunately Phaser has pretty good support for particles.  In this tutorial we are going to take a look at how they are used.

 

First, a quick introduction to particles.  A particle system is simply a mass of things, namely particles.  A particle is often ( as in this case ) a simple sprite.  The entire idea behind a particle system is to control a large number of particles using a single controller.  Particles are commonly used to create effects like fire and smoke, where each dozens, hundreds or thousands of smoke and flame particles are emitted ( pushed ) from the particle emitter.  As the emitter moves, so do the particles emitted from it.  This allows you to define over all behavior in the emitter, not each particle.  If that makes no sense, don’t worry, the examples below should clear it up.

 

Let’s take a look at a very basic emitter.  First we need a particle graphic.  In this case I am using the following graphic:

 

particle

 

It’s a simple transparent png image named particle.png.  Now the code:

 

/// <reference path="phaser.d.ts"/>

class SimpleGame {
    game: Phaser.Game;
    sound: Phaser.Sound;
    emitter: Phaser.Particles.Arcade.Emitter;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', { create: 
                    this.create, preload: this.preload});
    }
    preload() {
        // Load the image we are going to use for our particle
        this.game.load.image("particle", "particle.png");
    }
    create() {
        // Now we are creating the particle emitter, centered to the world
        this.emitter = this.game.add.emitter(this.game.world.centerX, this.game.
                       world.centerY);
        // Make the particles for the emitter to emmit.  We use the key for the 
        particle graphic we loaded earlier
        // We want 500 particles total
        this.emitter.makeParticles('particle', 1, 500, false, false);
        // And BOOM, emit all 500 particles at once with a life span of 10 
        seconds.
        this.emitter.explode(10000, 500);
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

Now when you run this code:

 

p1

 

500 particles using our png texture “explode” out of the emitter all at once.  The code is fairly heavily commented to explain what exactly is going on so I am going to move on to the next example.

 

Some ( most? ) of the time, you arent going to want all of your particles exploding all at once, except perhaps if you are modeling an explosion that is, instead you often want them to stream over time, perhaps from a moving source.  Also, you often want to use more than a single particle graphic for variety.  Finally, you often want those particles to physically interact with the world.  This example is going to do all of this.

 

This time we are going to use multiple (poorly edited by me) image files for our particles:

particleparticle2particle3

 

And now the code:

 

/// <reference path="phaser.d.ts"/>

class SimpleGame {
    game: Phaser.Game;
    sound: Phaser.Sound;
    emitter: Phaser.Particles.Arcade.Emitter;
    sprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload,
            update: this.update
        });
    }
    preload() {
        // This time we have 3 different particle graphics to use
        this.game.load.image("particle", "particle.png");
        this.game.load.image("particle2", "particle2.png");
        this.game.load.image("particle3", "particle3.png");

        this.game.load.image("logo", "gfslogo.png");
    }
    update() {
        // This checks for and handles collisions between our sprite and 
        particles from the emitter
        this.game.physics.arcade.collide(this.sprite, this.emitter);
    }
    create() {
        var start = new Date().getTime();
        for (var i = 0; i < 1e7; i++) {
            if ((new Date().getTime() - start) > 10000) {
                break;
            }
        }
        this.emitter = this.game.add.emitter(0, 0);
        // As you can see, you can pass in an array of keys to particle graphics
        this.emitter.makeParticles(['particle', 'particle2', 'particle3'], 1, 
                                   500, false, false);
        // Instead of exploding, you can also release particles as a stream
        // This one lasts 10 seconds, releases 20 particles of a total of 500
        // Which of the 3 graphics will be randomly chosen by the emitter
        this.emitter.start(false, 10000, 20, 500, true);

        // This line of code illustrates that you can move a particle emitter.  
        In this case, left to right across
        // The top of the screen.  Ignore details tweening for now if it's new, 
        we will discuss later
        this.game.add.tween(this.emitter).to({ x: this.game.width }, 10000,null,
                            true,0,1,true).start();

        // Let's create a sprite in the center of the screen
        this.sprite = this.game.add.sprite((this.game.width / 2) - 100, (this.
                      game.height / 2) - 100, "logo");
        // We want it to be part of the physics of the world to give something 
        for particles to respond to
        // Note, we will cover physics in more detail later ( after tweening 
                                                              perhaps... ;) )
        this.game.physics.enable(this.sprite);
        this.sprite.body.immovable = true;
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

And run it:

 

p2

 

As you can see, you can provide multiple particles, move the emitter and have it physically interact with the scene.  Don’t worry over much about tweening or physics, these are two subjects we will cover later in more detail.

 

In these two examples, we’ve looked at particles like you would use for special effects work, a very common situation.  That said, Particles can actually be used to control a large number of game entities that have common over all behavior, but randomized location, rotation, size or scale.  Take for example, a flight of animated birds.  You might want to add birds flying in the background of your game.  Let’s take a look at how to do this!

 

First I am using (a full sized version) of this sprite sheet taken from here.

robin-782x1024

 

It’s an animated sequence of a robin in flight.  It contains 22 frames, each 240x314 pixels in size.

 

Now let’s take a look at the code:

 

/// <reference path="phaser.d.ts"/>


// Create our own Particle class
class MyParticle extends Phaser.Particle {
    elapsedTime: number;
    currentFrame: number;
    static MAX_FRAME: number = 22;
    game: Phaser.Game;

    // In the constructor, randomly pick a starting frame of animation so all 
    the 
    // birds arent animated at the same rate
    constructor(game: Phaser.Game, x: number, y: number, key?: any, frame?: any) 
                {
        this.currentFrame = Math.floor(Math.random() * MyParticle.MAX_FRAME);
        this.elapsedTime = 0;
        this.game = game;

        // Now call Particle's constructor, passing in the spritesheet and frame 
        to use initially
        super(game, x, y, "ss", this.currentFrame);
    }

    update() {
        super.update();

        // Ever 100ms move to the next frame of animation
        this.elapsedTime += this.game.time.elapsed;
        if (this.elapsedTime >= 100) {
            this.currentFrame++;
            if (this.currentFrame > MyParticle.MAX_FRAME) this.currentFrame = 0;
            this.frame = this.currentFrame;
            this.elapsedTime = 0;
        }
    }
}

class SimpleGame {
    game: Phaser.Game;
    sound: Phaser.Sound;
    emitter: Phaser.Particles.Arcade.Emitter;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload:
            this.preload, render: this.render
        });
    }
    preload() {
        // Load the spritesheet containing the frames of animation of our bird
        // The cells of animation are 240x314 and there are 22 of them
        this.game.load.spritesheet("ss", "robin.png", 240, 314, 22);
    }
    render() {
    }
    create() {
        // Now we are creating the particle emitter, centered to the world
        this.emitter = this.game.add.emitter(this.game.world.centerX, this.game.
                       world.centerY);

        this.emitter.particleClass = MyParticle;
        this.emitter.makeParticles();
        
        // In this case, we dont want gravity affecting the birds and we dont 
        want them to rotate
        this.emitter.gravity = 0;
        this.emitter.minRotation = 0;
        this.emitter.maxRotation = 0;

        // Now start emitting particles.  Total life of 1000 seconds, create one 
        per 500ms ( 2/sec )
        // and create a total of 100 birds.
        this.emitter.start(false, 100000, 500, 100, true);
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

And when run:

 

p3

 

The terrible graphics are a side effect of being converted to an animated GIF that would take forever to download!

 

It just dawned on me that I haven’t actually covered Spritesheets yet… oops.  Hey, this is how you use a spritesheet! :)  Don’t worry if you struggle with the spritesheet portions, we will cover that later as well.  The important part here is the Particle itself.  In this example we extend the class Particle to create our own Particle class.  This class then handles updating itself resulting in the animation of the bird.  Obviously you could put a great deal more logic in there, although be sure to keep things pretty light computationally, especially if you intend to create a number of them.

 

This example actually illustrates a couple of really nice features of TypeScript, but maps nicely to Phaser’s JavaScript.  The first in the concept of a constructor.  This is code that is called as the object is created.  The next more important concept is class and extend.  In this case we are extending an existing JavaScript class, Particle.  A quick look behind the curtains now.

 

In TypeScript we write:

 

class MyParticle extends Phaser.Particle

 

This results in the JavaScript

 

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
// Create our own Particle class
var MyParticle = (function (_super) {
    __extends(MyParticle, _super);

 

Pretty cool stuff, and certainly easier to read and maintain.

 

A Small Bug

 

While writing this I ran into a small bug I figured I should make you aware of ( and one of the downsides of working with TypeScript ).  In the code sample we had the following line:

 

this.emitter.particleClass = MyParticle;

 

This line is specifying the type of class to use for a Particle, no an instance of the class.  Unfortunately the Phaser.d.ts file is incorrect in it’s definition.  It instead expects particleClass to receive a Phaser.Particle instance.  This is wrong ( and took some time to route out ).  In the definition, if not fixed by the time you read this, make the following edit to Emitter:

 

particleSendToBack: boolean;
// MJF Fix particleClass: Phaser.Sprite;
particleClass: any;

 

Hopefully that will be fixed by the time you read this.

 

Programming


19. August 2014

 

 

Now that we’ve covered input and graphics, it’s time we move on to audio.  Here is a bit of a warning upfront…

 

HTML5 audio sucks.

 

Yeah, that’s about it in nutshell.  This is one of those areas where games in HTML5 really suffer and sadly it doesn’t seem to be going away any time soon.  There are two major things to be aware of right up front.

 

First, audio file formats.  Different browsers support different file formats, but not all the same formats sadly.  You can read a pretty good chart on the topic right here.  In a nutshell, some support ogg, some support mp3, some support wav and some support m4a.  To make things even more fun, mp3 is a license encumbered format that could result in heavy licensing fees if your game is successful.  In reality, it’s never really enforced, but just the possibility should be enough to make you wary.  Fortunately, Phaser provides a way to deal with all of this that you will see shortly.

 

Second, well, Safari on iOS really kinda stinks at audio for a couple glaring reasons.  First and foremost, you can only play one sound or video at a time…  Yeah, really.  If you play a second sound, the first immediately stops.  Kinda. Big. Deal.  You can however work around this using an audio sprite, which is basically a bunch of audio files smashed together into a single file.  A second major failing is you can’t play audio on page load in Safari.  This means if you want to load your game up to a title screen with some music playing… you cant.  Audio can only be started in response to a users touch.  Yeah, this sucks too.  This one unfortunately you cannot work around, short of using a wrapper like CocoonJS for “natively” deploying your HTML5 game.

 

Through this all, you are probably going to need a tool to either merge your audio, or convert to a variety of formats.  Fortunately there is a free and excellent audio editor named Audacity available, that makes the process fairly painless.  In order to follow this tutorial, you are going to have to get an audio file and save it in mp3 and ogg format and add it to your project.

 

OK, enough about the HTML5 audio warts, let’s get to some code! 

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    sound: Phaser.Sound;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        this.game.load.audio("GameMusic", ["song.mp3","song.ogg"]);
    }
    create() {
        this.sound = this.game.add.audio('GameMusic');
        this.sound.play();
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

It’s important to note, this example wont actually work in Safari on iOS due to the limitation of only being able to play audio in response to a user touch.  You would have to change it so the play() call is done in a touch handler.

 

Here what you are doing is preloading audio using game.load.audio().  The parameters are the key to refer to the audio file, and a list of files to load.  This is where the magic happens, you should provide all supported file formats, then Phaser will serve the one that performs best on the browser the user is using.  M4A files perform the best on iOS, and don’t have the legal encumbrance that MP3, so OGG and M4A would probably be all you needed, but I may be wrong here.  If in doubt, provide all 3.

 

Now let’s look at an example that allows you to control playback of the sound file:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    sound: Phaser.Sound;
    playButton: Phaser.Button;
    pauseButton: Phaser.Button;
    stopButton: Phaser.Button;
    volUpButton: Phaser.Button;
    volDownButton: Phaser.Button;
    muteButton: Phaser.Button;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', { create: this.create, preload: this.preload, 
render
: this.render }); } preload() { this.game.load.audio("GameMusic", ["song.mp3", "song.ogg"]); this.game.load.image("button", "button.png", false); } render() { this.game.debug.soundInfo(this.sound, 0, 100); } create() { this.sound = this.game.add.audio('GameMusic'); // Set up sound event handlers on the sound object this.sound.onPlay.add(() => { alert("Played"); }); this.sound.onPause.add(() => { alert("Paused"); }); // Play Button this.playButton = this.game.add.button(0, 0, "button", () => { if (this.sound.currentTime > 0) this.sound.resume(); else this.sound.play(); } , this); this.playButton.addChild(new Phaser.Text(this.game, 17, 18, "Play", { fill: '#ff0000' })); // Pause Button this.pauseButton = this.game.add.button(95, 0, "button", () => { this.sound.pause(); } , this); this.pauseButton.addChild(new Phaser.Text(this.game, 12, 18, "Pause", { fill: '#ff0000' })); // Stop Button this.stopButton = this.game.add.button(190, 0, "button", () => { if (this.sound.isPlaying) { this.sound.stop(); this.sound.currentTime = 0; } } , this); this.stopButton.addChild(new Phaser.Text(this.game, 17, 18, "Stop", { fill: '#ff0000' })); // Volume Up Button this.volUpButton = this.game.add.button(300, 0, "button", () => { this.sound.volume += 0.1; } , this); this.volUpButton.addChild(new Phaser.Text(this.game, 17, 18, "Vol +", { fill: '#ff0000' })); // Volume Down Button this.volDownButton = this.game.add.button(400, 0, "button", () => { this.sound.volume -= 0.1; } , this); this.volDownButton.addChild(new Phaser.Text(this.game, 17, 18, "Vol -", { fill: '#ff0000' })); // Mute Button this.volDownButton = this.game.add.button(500, 0, "button", () => { // Global mute! Use this.sound.mute to mute a single sound this.game.sound.mute = !this.game.sound.mute; } , this); this.volDownButton.addChild(new Phaser.Text(this.game, 17, 18, "Mute", { fill: '#ff0000' })); } } window.onload = () => { var game = new SimpleGame(); };

 

Here is the resulting app:

 

 

It’s a bit of a monster, but most of the code is actually just wiring up the buttons.  There are a few important take away points here.  First, you can work with the local sound object, or all sounds globally using game.sound.  Second, each action on the sound file ( play, resume, stop, etc ) have an appropriate event handler you can implement.  I only did a couple in this example.  Finally, volume is a value from 0 to 1.  You can go above or below this range, but it wont actually do anything.  All said, once you get over the file format issues, playing audio is relatively straight forward.

 

Finally, let’s touch on audiosprites again for a second.  As mentioned earlier, an audiosprite is actually a bunch of audio files smashed together into a single file.

 

Consider the following sound effects.  A gun cocking ( http://www.freesound.org/people/woodmoose/sounds/177054/ ) and a gun shot ( http://www.freesound.org/people/18hiltc/sounds/228611/ ).  Load your first sound effect into audacity, like so:

image

 

Take note of the end of the file, in this case 0.785 seconds.

 

Now, select File->Import-> Audio

image

 

Import your additional sound effects, in this case I’m opening the gunshot file.  You should now have two tracks in Audacity, like so:

image

 

Now select the bottom track by double clicking.  It should highlight in gray, like so:

image

Now click at the end of the first track and paste ( CTRL + V, or EDIT->Paste ).  You should now have a single track that looks like this:

image

 

Now save this file ( might as well create OGG, MP3 and M4A versions while you are at it ).

 

Now lets take a look how we use it in code.

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    sound: Phaser.Sound;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', { create: this.create, preload: this.preload, 
render
: this.render }); } preload() { this.game.load.audio("sfx", ["GunSounds.ogg", "GunSounds.wav"]); } render() { this.game.debug.soundInfo(this.sound, 0, 100); } create() { this.sound = this.game.add.audio('sfx'); this.sound.addMarker("gunCock", 0, 0.785); this.sound.addMarker("gunShoot", 0.786, 1.49); this.sound.play("gunCock"); this.sound.onMarkerComplete.add(() => { this.sound.play("gunShoot"); }); } } window.onload = () => { var game = new SimpleGame(); };

 

This plays the first sound, then immediately once it is complete, it plays the other.  As you can see, you do so by setting markers within the entire sound file.  0.785 is the length of the first sound effect, then 1.49 is the length of the entire file.  You simply name each marker, then give it’s start and end locations within the file.  You can get these values using an audio editor, such as audacity.  This allows you to load all of your similar sound effects into a single quicker to load file and should help you work around the single sound stream limitations of iOS.

 

Programming


11. August 2014

 

 

In the previous tutorial, which I will admit… some time has elapsed since I wrote it, sorry about that… anyways, in the last tutorial we looked at handling keyboard input using Phaser.  In this tutorial we are going to look at handling mouse and touch events.  Just like the last part, this one is going to be relatively light on explanation and high on code.

 

Ok, let’s jump right in.  The first example shows how to poll for mouse/touch information:

 

/// <reference path="phaser.d.ts"/>

// This code demonstrates polling for touch or mouse clicks
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload, update: this.update
        });
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        this.jetSprite.pivot.x = this.jetSprite.width / 2;
        this.jetSprite.pivot.y = this.jetSprite.height / 2;
    }

    update() {

        // You can poll mouse status
        if (this.game.input.activePointer.isDown) {
            // This will be set to true if any mouse button is pressed or a finger is touched
            this.jetSprite.position.set(this.game.input.mousePointer.x,
                this.game.input.mousePointer.y);

            // You can test if the user is using a mouse
            if (this.game.input.activePointer.isMouse) {
                // In the case of a mouse, you can check mouse button status
                if (this.game.input.activePointer.button == Phaser.Mouse.RIGHT_BUTTON) {

                    // We just want to clear it, so this doesnt fire over and over, dont do this in production
                    this.game.input.activePointer.reset();
                    alert("Right button pressed");
                }
            }
            else {
                // On the other hand, if you are dealing with touch, you can have multiple touches/pointers
                // By default there are two pointers defined, so you can have up to two touches.
                // You can add more pointers using input.addPointer();
                if (this.game.input.pointer1.isDown && this.game.input.pointer2.isDown)
                    alert("Multitouch!");
            }
        }
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

 

Pointer is an abstraction for both touch and mouse.  As you can see above, there are multiple pointers ( input.pointer1, input.pointer2, etc… ) but by default only two will be enabled.  If you want to handle multitouch with more than 2 fingers you need to register more using addPointer().   You can add up to 10 pointers total.  pointer1 is the first finger to touch the screen, pointer2 the second, etc.

 

Now let’s take a look at handling mouse input using callbacks instead of polling:

 

/// <reference path="phaser.d.ts"/>

// This code demonstrates polling for touch or mouse clicks
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload
        });
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        this.jetSprite.pivot.x = this.jetSprite.width / 2;
        this.jetSprite.pivot.y = this.jetSprite.height / 2;

        // You can handle mouse input by registering a callback as well
        // The following registers a callback that will be called each time the mouse is moved
        this.game.input.moveCallback = (pointer:Phaser.Pointer,x:number,y:number) => {
            this.jetSprite.position.set(x, y);
        }

        // This one registers a mouse click handler that will be called
        this.game.input.onDown.add(SimpleGame.prototype.mouseDown);

    }

    mouseDown(event:MouseEvent) {
        alert("Mouse is down " + event.button);
    }

}

window.onload = () => {
    var game = new SimpleGame();
};

 

 

In this case we register a function that will be called whenever the mouse moves.  In this case I am using an anonymous delegate.  You can also handle mouse down or touch events.  The format is slightly different as onDown is a Signal instead of a callback.  That said, a Signal is basically a wrapper around a callback function, so it’s not really all that different.  Except of course with Signals, you can register multiple for the same event.

 

Finally, in the previous two examples, we handled the input at an application level.  If it makes sense for your game, you can actually handle input at the Sprite level.  Like so:

 

/// <reference path="phaser.d.ts"/>

// In this example we illustrate input events can be applied to Sprites
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload
        });
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        this.jetSprite.pivot.x = this.jetSprite.width / 2;
        this.jetSprite.pivot.y = this.jetSprite.height / 2;

        // First enable the sprite to receive input
        this.jetSprite.inputEnabled = true;
        
        // Then add an event handler for input over
        this.jetSprite.events.onInputOver.add(() => {
            alert("The mouse passed over the sprite!");
        });
    }


}

window.onload = () => {
    var game = new SimpleGame();
};

 

 

First thing you need to do is tell Phaser that your Sprite will handle input by setting inputEnabled to true.  Next we add an input handler for onInputOver, which once again is a Signal.  There are a number of events that Sprite can respond to, all predictably enough in the events class.

 

As a side note, part of the delay in updating this tutorial series is I was actually intending to write one about using GamePads.  First I started writing code and my XBox 360 wireless receiver died horribly.  Apparently this is a very common problem with them, a tiny little fragile fuse broke.  I then ordered a replacement from Amazon and it took three weeks to arrive.  Then when it did arrive, well…

 

Let’s just say Gamepad support in HTML5 is complete and utter garbage.  There are a bunch of projects in the works, but they are all a far way away from being actually usable.  If you are looking to add gamepad support to your HTML5 project, expect it to be very browser specific.  By this I actually mean exact version of the browser…  The APIs are changing constantly and are breaking just as often.  In my opinion, it’s simply not worth it at this point.

 

Programming


24. June 2014

 

 

In the previous part we looked at handling graphics in Phaser, now we are going to look at handling input.  This part is going to be code heavy and fairly light on description.  Look to the code comments for more details.

As is pretty common with game frameworks, there are a number of different ways to handle input and a number of different devices, so lets get started!

 

Using the cursor keys and polling for input

 

/// <reference path="phaser.d.ts"/>

// Demonstrate the use of arrow keys in a Phaser app
// This application demonstrates creation of a Cursor and polling for input
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;
    cursors: Phaser.CursorKeys;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload,
        update: this.update});
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // create the cursor key object
        this.cursors = this.game.input.keyboard.createCursorKeys();
    }

    update() {
        // Update input state
        this.game.input.update();

        // Check each of the arrow keys and move accordingly
        // If the Ctrl Key + Left or Right arrow are pressed, move at a greater rate
        if (this.cursors.down.isDown)
            this.jetSprite.position.y++;
        if (this.cursors.up.isDown)
            this.jetSprite.position.y--;
        if (this.cursors.left.isDown) {
            if (this.cursors.left.ctrlKey)
                this.jetSprite.position.x -= 5;
            else
                this.jetSprite.position.x--;
        }
        if (this.cursors.right.isDown) {
            if (this.cursors.right.ctrlKey)
                this.jetSprite.position.x += 5;
            else
                this.jetSprite.position.x++;
        }
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

When you run this code the familiar jet sprite is rendered centered to the canvas. You can then use the arrow keys to move the fighter around.  As you can see, in the state for each key is information on modifier keys like Control and Alt.  Polling for input ( that is, checking status each call to update ) is a valid way of controlling a game, but sometimes you instead want to respond to input as it arrives.  Let’s look now at an example of event driven keyboard handling:

 

/// <reference path="phaser.d.ts"/>

// Demonstrate keyboard input handling via callback
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;
    W: Phaser.Key;
    A: Phaser.Key;
    S: Phaser.Key;
    D: Phaser.Key;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload
        });
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    moveLeft() {
        this.jetSprite.position.add(-1, 0);
    }
    moveRight() {
        this.jetSprite.position.add(1, 0);
    }
    moveUp(e: KeyboardEvent) {
        // As you can see the event handler is passed an optional event KeyboardEvent
        // This contains additional information about the key, including the Control
        // key status.
        // Basically if the control key is held, we move up or down by 5 instead of 1
        if (e.ctrlKey) 
            this.jetSprite.position.add(0, -5);
        else
            this.jetSprite.position.add(0, -1);
    }
    moveDown(e: KeyboardEvent) {
        if (e.ctrlKey)
            this.jetSprite.position.add(0, 1);
        else
            this.jetSprite.position.add(0, 1);
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // Create a key for each WASD key
        this.W = this.game.input.keyboard.addKey(Phaser.Keyboard.W);
        this.A = this.game.input.keyboard.addKey(Phaser.Keyboard.A);
        this.S = this.game.input.keyboard.addKey(Phaser.Keyboard.S);
        this.D = this.game.input.keyboard.addKey(Phaser.Keyboard.D);

        // Since we are allowing the combination of CTRL+W, which is a shortcut for close window
        // we need to trap all handling of the W key and make sure it doesnt get handled by 
        // the browser.  
        // Unfortunately you can no longer capture the CTRL+W key combination in Google Chrome
        // except in "Application Mode" because apparently Google thought an unstoppable un prompted
        // key combo of death was a good idea...
        this.game.input.keyboard.addKeyCapture(Phaser.Keyboard.W);

        // Wire up an event handler for each K.  The handler is a Phaser.Signal attached to the Key Object
        this.W.onDown.add(SimpleGame.prototype.moveUp, this);
        this.A.onDown.add(SimpleGame.prototype.moveLeft, this);
        this.S.onDown.add(SimpleGame.prototype.moveDown, this);
        this.D.onDown.add(SimpleGame.prototype.moveRight, this);
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

As you can see, you can also create Phaser.Key objects and attach onDown event handlers ( technically Signals ) to each.  Of course you can reuse the same handler for multiple keys.  A couple key things to notice here… unlike the previous example, holding down a key will not cause continuous movement.  You must press and release the key over and over.  If you want constant movement, either use a polling method, use and action instead of updating each frame, or add some logic to move until the key is released.

 

The other thing to be aware of here is the use of the CTRL+W combination and addKeyCapture().  addKeyCapture() allows you to prevent the event from bubbling up, so once you’ve handled the key combination, it’s done.  Otherwise it would keep being passed up, either to other objects in the scene, or to the browser itself.  You can also use addKeyCapture to prevent default web behavior, such as scrolling when SPACE is pressed.

 

Programming


9. June 2014

 

 

I’ve done a number of these walk through type tutorials using many different languages/libraries and there is one common traffic trend.  People LOVE reading about graphics.  In every single example the post I do about graphics always seems to draw the most traffic.  I guess we just love drawing stuff on screen.  Now for the good part, Phaser is good at it and makes it really all quite easy.

 

Loading and adding a sprite

 

Back in the previous post I actually jumped the gun a bit and showed preloading and rendering sprites.  Since so many people jump ahead straight to the graphics post, I’ll review the process.

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    titleScreenImage: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        this.game.load.image("title", "TitleScreen.png");
    }
    create() {
        this.titleScreenImage = this.game.add.sprite(0, 0, "title");
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

The key concepts to be aware of here is preloading assets using game.load methods, where you pass in the filename as well as a unique string key that you will use to access the asset.  Then in create you can see this in action, where we add a sprite to the game using game.add.sprite, using the key “title” to access it.  In this case our “sprite” was a full screen image.  Now let’s look at how you can work with a sprite, this time using a slightly smaller image.

Working with sprites

 

For this section I am going to work with this sprite ( created in this tutorial series ):

jet

 

Add it to your project’s root directory.  In my case I’ve called it jet.png.  Using the above code, simply replace “TitleScreen.png” with “jet.png” and “title” with “jet” and you should see:

 

image

 

 

As you can see, our sprite is drawn at the top left corner of the screen.  That is because the value (0,0) in Phaser refers to the top left corner of the screen by default.  Let’s instead center our sprite using the following code:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }
    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

Run this code and:

image

 

We are now nicely centered, both to the window and sprite.

We have one major challenge with centering the image.  Until the sprite is created, it doesn’t have a width or height.  However, when you create the sprite you can set it’s position.  Of course it would be possible to create then move the sprite but that is hackish and could have unintended graphical problems.  Instead we can get the image we loaded using this.game.cache.getImage() then access the images dimensions.  One line of code might stand out for you here:

 

var image = <Phaser.Image>this.game.cache.getImage("jet");

 

This is TypeScript’s way of typecasting.  If you’ve worked in Java, C# or C++ you’ve no doubt encountered typescasting.  If your experience was mostly in JavaScript ( a mostly typeless language ), this might be new to you.  Basically what you are saying is “we promise the value returned by getImage() is of the type <Phaser.Image>, so make image a Phaser.Image”.  If you try to access a value or method in image that doesn’t exist in Phaser.Image, TypeScript will give you an error.

 

Positioning items in Phaser

 

When using a sprite, by default, transformations happen relative to the top left corner of the sprite.  This is why we had to subtract half to the width and height of the sprite when positioning it in the center of the screen.  Otherwise the top left corner of the sprite would be centered to the screen like this:

image

 

Sometimes however you would rather transform the sprite relative to a different point, commonly the very middle or occasionally the bottom left corner.   Fortunately there is an option for this, the anchor.  The anchor tells Phaser where to draw your Sprite relative to.  Here we set the anchor to the center of the sprite then draw it at (0,0) like so:

 

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        this.jetSprite.anchor.set(0.5,0.0)
        this.jetSprite.position.x = this.jetSprite.position.y = 0.0;
    }

 

And the result:

image

As you can see, draw calls for the sprite now position relative to it’s center.  Positioning sprites relative to their center is incredibly handy when it comes to rotation, while anchoring at the bottom is useful for platformers where you are aligning the sprite’s feet to the ground.  What you chose is entirely up to you.  The values passed in to anchor might be a bit confusing, as they are normalized, meaning they go from 0 to 1.  The values are all relative to the sprite itself, while (0,0) is the top left corner of the sprite, while (1,1) is the bottom right corner.  (1,0) would be the bottom left, while (0,1) would be the top right.

 

There is one important thing to be aware of here.  Anchor works relative to the source image, not the sprite itself.  Therefore if you intend to scale your sprites, instead of using anchor, you are going to want to use pivot instead.  (Until recently pivot was broken, but it appears to work now).  Pivot sets the center point of the sprite, not the image that composes the sprite.  Setting the pivot looks like this:

        this.jetSprite.pivot.x = this.jetSprite.width / 2;
        this.jetSprite.pivot.y = this.jetSprite.height / 2;

 

Again, you don’t have to set the anchor at all, but it can be useful.  Unlike anchor, pivot uses relative pixel coordinates within the sprite itself.  Therefore the mid-point is at (width/2,height/2).  Once again, (0,0) is the top left corner.

 

Simple Graphics

 

Sometimes you just want to draw primitive graphics on screen… lines, circles, boxes, that kind of stuff.  Fortunately Phaser has that built in as well in the form of the Graphics object.

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }
    create() {
        // Add a graphics object to our game
        var graphics = this.game.add.graphics(0, 0);

        // Create an array to hold the points that make up our triangle
        var points: Phaser.Point[] = [];
        // Add 4 Point objects to it
        points.push(new Phaser.Point());
        points.push(new Phaser.Point());
        points.push(new Phaser.Point());

        // Position one top left, top right and botto mmiddle
        points[0].x = 0;
        points[0].y = 0;

        points[1].x = this.game.width;
        points[1].y = 0;

        points[2].x = this.game.width/2;
        points[2].y = this.game.height;

        // set fill color to red in HEX form.  The following is equal to 256 red, 0 green and 0 blue.  
        // Do at 50 % alpha, meaning half transparent
        graphics.beginFill(0xff0000, 0.5);
        
        // Finally draw the triangle, false indicates not to cull ( remove unseen values )
        graphics.drawTriangle(points, false);

        // Now change colour to green and 100% opacity/alpha
        graphics.beginFill(0x00ff00, 1.0);

        // Draw circle about screen's center, with 200 pixels radius
        graphics.drawCircle(this.game.width / 2, this.game.height / 2, 200);
        
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

The code is pretty heavily commented so should be self explanatory.  When you run it you should see:

image

 

 

A look behind the scenes

 

Let’s take a quick look at how graphics drawing works in Phaser.  That involves going back to this line:

this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', {});

Here you are passing in a lot of important information.  First (and second) are the resolution of your game.  Next is the type of Renderer that Phaser should use.  We mentioned this briefly in the prior tutorial.  You have the option of WEBGL or Canvas rendering ( or headless, which means no rendering at all and is used for server side programming ).  Which you chose depends heavily on the device you are supporting.  For example, currently no iOS devices support WebGL and only the most recent version of Internet Explorer work.  By selecting AUTO you let Phaser decide based on the device you are running on.  Finally ‘content’ is the HTML ID of the DIV to render our game in.

 

You may notice scattered throughout Phaser’s code/documentation are references to PIXI.  Pixi.js is a popular WebGL 2D renderer that is able to fallback on Canvas rendering when WebGL is unavailable.  Pixi is the renderer that Phaser uses, so you will occasionally see Pixi classes inside Phaser code.

 

There is one final thing to cover about graphics before moving on, full screen and handling multiple resolutions.

 

Going Full Screen

 

Now let’s take a look at an application that can go full screen:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    // This function is called when a full screen request comes in
    onGoFullScreen() {
        // tell Phaser how you want it to handle scaling when you go full screen
        this.game.scale.fullScreenScaleMode = Phaser.ScaleManager.EXACT_FIT;
        // and this causes it to actually do it
        this.game.scale.refresh();
    }
    goFullScreen() {

    }
    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");

        // Draw the jet image centered to the screen
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // Set background to white to make effect clearer
        this.game.stage.backgroundColor = 0xffffff;

        // Add a function that will get called when the game goes fullscreen
        this.game.scale.enterFullScreen.add(SimpleGame.prototype.onGoFullScreen, this);

        // Now add a function that will get called when user taps screen.
        // Function declared inline using arrow (=>) function expression
        // Simply calls startFullScreen().  True specifies you want anti aliasing.
        // Unfortunately you can only make full screen requests in desktop browsers in event handlers
        this.game.input.onTap.add(
            () => { this.game.scale.startFullScreen(true); },
            this);
    }

}

window.onload = () => {
    var game = new SimpleGame();
};

 

The comments cover most of what’s going on, but I thought I would touch on a couple things in the above example.  First you cant simply request to go fullScreen in Desktop browsers for security reasons.  This means your game can’t simply start in full screen, you need to make the call to startFullScreen() inside an event handler.  Most commonly this will be in the form of a “Click here for FullScreen” button or link.

 

Next is the ()=> syntax, known in TypeScript as an arrow function expression (if you’ve used C#, this syntax is going to look awfully familiar to you!) and is something that should be coming in the next JavaScript version (ECMAScript 6).  It is simply a more compact form of a function expression ( no need for the word function ) that is automatically scoped to “this”.  You could have created a function like onGoFullScreen like we did for enterFullScreen.  ( Coincidentally we could have also handled enterFullScreen using an arrow function.

 

The last thing to look at is the scale mode.  In this example we used Phaser.ScaleManager.EXACT_FIT, which scales the scene up to match your resolution.  There are two other options, SHOW_ALL and NO_SCALE.  Here is the result of running the code above using each setting:

 

Phaser.ScaleManager.EXACT_FIT

EXACT_FIT

 

Phaser.ScaleManager.NO_SCALE

NO_SCALE

 

Phaser.ScaleManager.SHOW_ALL 

SHOW_ALL

 

If you have an HDTV, you can think about them this way.  EXACT_FIT is the same as Stretch mode.  It scales the scene to use as much of the screen as possible, but can result in some distortion.  NO_SCALE does nothing, it simply shows the scene un-altered, centered to the screen.  SHOW_ALL is about the equivalent of Letterbox.  Basically it fits as well as it can while maintaining the aspect ration of your original scene. 

 

Don’t worry, that’s not it for graphics, we have all kinds of things coming up…  spritesheets, effects, particles, animation, etc…  That’s just it for the foundations.

 

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List