This will be the first part in a new series I plan on creating for creating HTML5 games with the Phaser framework. We will be focusing on how to create bare-bones versions of common game mechanics with Phaser.
The same basic game mechanics can be used to create a multitude of different styles of games. Take puzzle games like Bejeweled or Candy Crush, many of these games use the exact same mechanics (with some differences of course), they just have a different coat of paint over those core mechanics. Running platformers is another good example, the core game mechanic is a side-scrolling environment where a player can jump between platforms.
Before adding things like animated sprites, backgrounds, and sound effects to games, I like to get the basic mechanics working in the simplest way possible. This usually means using basic squares for the player’s character and the environment. The bells and whistles like great artwork and sounds are what make a game great, but it takes a lot of time to get these things right. By focusing on just the core mechanics first, you will quickly be able to tell if the mechanics are fun or not before investing too much time.
In this tutorial, we are going to build the basic mechanics for a helicopter style game. I remember spending way too much school time playing this game as a kid.
Here’s what it will look like when we are done:
Before we Get Started
This tutorial uses the ES6 template described in this tutorial. It is not necessary to read that tutorial before attempting this tutorial, but it may help give some context – especially if you are not familiar with ES6 and how to structure a Phaser game with ES6. You will need to have both Git and Node installed to complete this tutorial.
You should also have a basic understanding of how Phaser games work before attempting this tutorial, as I will not be covering all of the basics here. If you are not familiar with Phaser, I do have more tutorials available.
1. Generate a New Phaser Project
We will start off by generating a new Phaser game based on the ES6 template with the following command:
git clone https://github.com/joshuamorony/phaser-es6-boilerplate phaser-helicopter
Once that has finished downloading you should make that game your current working directory:
cd phaser-helicopter
and then install all of the dependencies with the following command:
npm install
to view your game at any time you can run the following command:
npm start
and then go to the following address in your browser:
http://localhost:3000
2. Create the Helicopter
We are going to start off by creating an object for our Helicopter. It doesn’t necessarily have to be a helicopter, it could just as easily be a bird or a superhero depending on what sprite you end up using, but we are going to refer to it as a helicopter.
The Helicopter
object will be responsible for handling everything related to the helicopter, and we will import it into our Main
state to use in the game. If you’re using the phaser boilerplate I linked above you will already have an ExampleObject
set up, so we are just going to reuse that.
Rename src/objects/ExampleObject.js to src/objects/Helicopter.js and add the following:
class Helicopter {
constructor(game) {
this.game = game;
this.isRising = false;
this.sprite = null;
}
spawn() {
let helicopterSprite = new Phaser.Graphics(this.game)
.beginFill(Phaser.Color.hexToRGB('#2c3e50'), 1)
.drawRect(0, 0, 100, 100);
let helicopterSpriteTexture = helicopterSprite.generateTexture();
this.sprite = this.game.add.sprite(
this.game.world.centerX,
this.game.world.centerY,
helicopterSpriteTexture
);
this.game.physics.arcade.enable(this.sprite);
this.sprite.enableBody = true;
this.sprite.body.gravity.y = 5000;
this.sprite.body.velocity.y = -1500;
this.sprite.body.collideWorldBounds = false;
this.sprite.anchor.setTo(0.5, 0.5);
}
setRising() {
this.isRising = true;
}
setFalling() {
this.isRising = false;
}
increaseVerticalVelocity() {
this.sprite.body.velocity.y -= 200;
}
isOutOfBounds() {
let position = this.sprite.body.position.y;
return position > this.game.world.height || position < 0;
}
}
export default Helicopter;
The spawn
method is what will handle adding the helicopter to the game. Instead of using an image for the sprite, we first programmatically create our own texture
by using the Phaser Graphics library. This allows us to create shapes just like we would with an HTML5 canvas, so we don’t need to worry about creating an image and loading it in, we can just create a simple square. We then use that texture
when creating the sprite. We also set some physics up on the sprite so that it will fall to the ground by default, and we give it an initial upwards velocity to give the player some time to react before it falls and dies.
We also set up a few helper methods in here that we will reference in our Main
state. We are able to set whether the helicopter is rising or not (this will be based on whether the user is currently clicking or tapping the screen), we have a method to increase the helicopters upwards velocity and a method to check if the helicopter is out of bounds (above or below the edge of the screen).
3. Add Controls for the Helicopter
Now that we have our helicopter object created, we are going to import it into our Main
state and set up some controls for it.
Modify src/states/Main.js to reflect the following:
import Helicopter from 'objects/Helicopter';
class Main extends Phaser.State {
create() {
//Enable Arcade Physics
this.game.physics.startSystem(Phaser.Physics.ARCADE);
//Set the games background colour
this.game.stage.backgroundColor = '#cecece';
this.helicopter = new Helicopter(this.game);
this.helicopter.spawn();
this.addControls();
}
update() {
// Check if out of bounds
if (this.helicopter.isOutOfBounds()) {
this.gameOver();
}
// Check if helicopter is rising
if (this.helicopter.isRising) {
this.helicopter.increaseVerticalVelocity();
}
}
addControls() {
this.game.input.onDown.add(this.helicopter.setRising, this.helicopter);
this.game.input.onUp.add(this.helicopter.setFalling, this.helicopter);
}
gameOver() {
this.game.state.restart();
}
}
export default Main;
We import the Helicopter
class at the top of the file, and then we create a new object using it in the create
method. We then call its spawn
method to add it to the game. At this point, the helicopter will be added to the screen, but it will just immediately fall to the bottom because we have no way to control it.
So, we add a call to addControls
where we set up an onDown
and onUp
event listener. When the user taps or clicks, the helicopter will have its isRising
value set to true, and when the user lets go the value will be set back to false
. We use this value in the update
method to decide whether or not we call the helicopter’s increaseVerticalVelocity
method. The end result is that when a user is tapping or clicking the helicopter will rise, and when they let go it will fall (due to the gravity we set earlier).
We also make a call to the isOutOfBounds
method to see if the helicopter is within the bounds of the game or not, and if it isn’t, we trigger the gameOver
method which will restart the game.
Here’s what you should have currently:
4. Create the Obstacles
We’ve got the mechanics for the helicopter working quite well, but we’re still missing a key component of the core game mechanic and that’s some obstacles to dodge. We’re going to add that now by using a similar approach to what we did with the helicopter. We will be creating a MovingWalls
object.
Add a file at src/objects/MovingWalls.js and add the following:
class MovingWalls {
constructor(game) {
this.game = game;
this.wallGroup = null;
this.spriteGroup = null;
this.wallSpeed = 300;
let seed = Date.now();
this.random = new Phaser.RandomDataGenerator([seed]);
this.initWalls();
}
initWalls() {
this.wallHeight = this.random.integerInRange(
20,
this.game.world.height / 3
);
this.wallWidth = 200;
let wallSprite = new Phaser.Graphics(this.game)
.beginFill(Phaser.Color.hexToRGB('#e74c3c'), 1)
.drawRect(0, 0, this.wallWidth, this.wallHeight);
let wallSpriteTexture = wallSprite.generateTexture();
this.spriteGroup = this.game.add.group();
this.spriteGroup.enableBody = true;
this.spriteGroup.createMultiple(10, wallSpriteTexture);
}
spawn() {
let wall = this.spriteGroup.getFirstDead();
wall.body.gravity.y = 0;
wall.reset(
this.game.world.width,
this.random.integerInRange(0, this.game.world.height)
);
wall.body.velocity.x = -this.wallSpeed;
wall.body.immovable = true;
//When the block leaves the screen, kill it
wall.checkWorldBounds = true;
wall.outOfBoundsKill = true;
}
}
export default MovingWalls;
This is a very similar idea to the Helicopter
except for a couple key differences. Instead of spawning a single sprite, we are creating a group of sprites, so we initially create 10 sprites in a group using:
this.spriteGroup.createMultiple(10, wallSpriteTexture);
then when we need to spawn a wall, we just use one of the sprites in this group that aren’t currently being used by using the getFirstDead
method. This allows us to recycle our sprites rather than constantly creating new ones, which is a lot better for performance.
To spawn a wall, we just grab one of our unused sprites and reset its position to the right side of the world. We give it a negative velocity so that it travels to the left of the screen which is what simulates movement in our game (our helicopter doesn’t move to the right, the whole game world moves around the helicopter to the left). We also need to make sure to set the checkWorldBounds
and outOfBoundsKill
properties so that the walls are killed
when they leave the game space (if we don’t kill them, then we can’t recycle them).
Now we just need to make use of these walls in our Main
state.
Modify src/states/Main.js to reflect the following:
import Helicopter from 'objects/Helicopter';
import MovingWalls from 'objects/MovingWalls';
class Main extends Phaser.State {
create() {
//Enable Arcade Physics
this.game.physics.startSystem(Phaser.Physics.ARCADE);
//Set the games background colour
this.game.stage.backgroundColor = '#cecece';
this.helicopter = new Helicopter(this.game);
this.helicopter.spawn();
this.walls = new MovingWalls(this.game);
this.addControls();
this.addTimers();
}
update() {
this.game.physics.arcade.overlap(
this.helicopter.sprite,
this.walls.spriteGroup,
this.gameOver,
null,
this
);
// Check if out of bounds
if (this.helicopter.isOutOfBounds()) {
this.gameOver();
}
// Check if helicopter is rising
if (this.helicopter.isRising) {
this.helicopter.increaseVerticalVelocity();
}
}
addControls() {
this.game.input.onDown.add(this.helicopter.setRising, this.helicopter);
this.game.input.onUp.add(this.helicopter.setFalling, this.helicopter);
}
addTimers() {
this.game.time.events.loop(2000, this.walls.spawn, this.walls);
}
gameOver() {
this.game.state.restart();
}
}
export default Main;
We’ve added an addTimers
method that will set up a loop that will call the walls spawn
method once every 2 seconds. We also add an overlap
check in the update
method that will detect collisions between the helicopter and any of the walls. If a collision occurs, then we call the gameOver
method.
The game should now look like this:
Summary
This game is far from being completed, but the core game mechanics are there now. You could quickly make the game look a lot more interesting by adding sprites for the helicopter and for the walls, and by adding a more interesting background. You might also want to add more bells and whistles, like music, collision sound effects, power-ups the player can collect, and so on.
These things can be added incrementally, all while maintaining a working game. I find this to be a much more manageable approach rather than trying to add in everything right from the start.