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:
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:
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:
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:
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.
It’s an animated sequence of a robin in flight. It contains 22 frames, each 240×314 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:
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.