Since starting with Ionic 2 I’ve fallen in love with ECMAScript 6 (ES6), and once I started working with Phaser again it just didn’t feel as nice working with ES5. In this tutorial I am going to show you how you can use ES6 in your own Phaser games, but first let’s talk a little bit about what ES6 even is.
A Little About ECMAScript 6 (ES6)
I won’t spend too long talking about this since I have already covered it in the past, but ES6 is essentially the next iteration of JavaScript. It is a specification (which is yet to be implemented by browsers) that adds some new features to the JavaScript you’re probably used to.
There’s quite a few useful things that have been added, but the most important things that will make a big impact on our Phaser games are classes:
class Shape {
constructor(id, x, y) {
this.id = id;
this.move(x, y);
}
move(x, y) {
this.x = x;
this.y = y;
}
}
and modules:
// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
// someApp.js
import * as math from 'lib/math';
console.log('2π = ' + math.sum(math.pi, math.pi));
// otherApp.js
import { sum, pi } from 'lib/math';
console.log('2π = ' + sum(pi, pi));
These two features lend themselves well to creating well structured, modular projects. We can create classes that handle one specific feature, and import them wherever we want to use it. That isn’t to say that we couldn’t take a similar modular approach with ES5, but these new features make it a lot easier and cleaner.
We are going to talk through these features a bit more in the post, but if you’d like a more detailed explanation of new ES6 features then I would recommend that you read this post.
Since it is not supported by browsers yet, we need to use some extra tools to transpile the ES6 code we write, into ES5 code that can be understood by browsers.
Using ES6 with Phaser Games
The journey to start using ES6 with my Phaser games didn’t take long because I came across this great boilerplate created by Daniel Belohlavek. Out of the box it has everything set up that you need to transpile and run ES6 code with Phaser, and it also allows you to:
- Run a development build with a single command
- Run a production build with a single command
- Live reload with Browsersync
- Minified production code
As soon as you make a code change and save it, your game will automatically refresh to show those changes. Best of all, since we’re using Node you don’t have to worry about setting up an XAMPP web server or anything like that to run your game locally.
I have forked this repository to create a new template that has some more boilerplate code which more closely reflects the template I have been using and giving out in the past, and it also includes a few examples.
Daniel has done an amazing job with the template though, I’ve just added a few bells and whistles, so kudos to him for that.
Installation
Before getting started you must have both Git and Node installed on your machine, so make sure to take care of that first.
To start a new project using the ES6 template, you can simply clone the template into a new folder using the following command:
git clone https://github.com/joshuamorony/phaser-es6-boilerplate my-game-name
You will then need to install all of the dependencies, so you should run:
cd my-game-name
and then run:
npm install
Once that has finished running your project is ready to use. Now all you have to do is run:
npm start
to set up the server and live reloading, and you can view your game by going to:
http://localhost:3000
in your browser. You can also run a minified production build with the following command:
npm run production
Now that we’ve got everything up and running, let’s talk through how we can use it.
Structure
The structure of this project is quite a bit different to what you may be used to if you’ve been using ES5. In the template I’ve been giving out on this blog for my tutorials there are 5 different states:
- Boot
- Preload
- GameTitle
- Main
- GameOver
and I’ve added these into the ES6 template as well, it just looks a little different, so let’s talk through that a bit.
You will find the source code for the application (where you will be making edits) in the src folder. This is split up into objects and states. All the states for your game (like the ones listed above) will go into the states folder, and you can use the objects folder to store any services the game might be using (I’ve created a Weather object and a DayCycle object for example).
You may also notice that there is a static folder. This is where your “static” content like images, JSON files, css files etc. would go and where you can modify the index.html file if necessary.
The build process that is configured in the template will combine all of the code in your src* folder into a single **game.js file, and it will copy that along with your static assets to the build folder. You should never modify this build folder, it is just where the “compiled” version of your game will live after being built. Any changes you make here would be overwritten by new builds.
Code
As well as the structural differences, the code itself also looks a little bit different. Let’s take a look at one of the states as an example:
import ExampleObject from 'objects/ExampleObject';
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';
//Example of including an object
//let exampleObject = new ExampleObject(this.game);
}
update() {}
}
export default Main;
This is the Main state and it should look pretty familiar. We are still using the create and update methods that are part of the Phaser game lifecycle, but the syntax is a bit different.
Instead of using functions and prototypes to create a class like structure (since ES5 doesn’t provide classes), we are just using actual classes which are available in ES6.
The most confusing thing here might be the import and export keywords. In ES6, by exporting something we make it available to import somewhere else. So at the top of this file we are importing the ExampleObject class from the objects folder. If we take a look at that class:
class ExampleObject {
constructor(game) {
//Do something
}
}
export default ExampleObject;
You will see that we export it. If we did not export ExampleObject here, then it would not be available to import into our Main state. Similarly, if you look at the index.js file:
import Boot from 'states/Boot';
import Preload from 'states/Preload';
import GameTitle from 'states/GameTitle';
import Main from 'states/Main';
import GameOver from 'states/GameOver';
class Game extends Phaser.Game {
constructor() {
super(
window.innerWidth * window.devicePixelRatio,
window.innerHeight * window.devicePixelRatio,
Phaser.AUTO
);
this.state.add('Boot', Boot, false);
this.state.add('Preload', Preload, false);
this.state.add('GameTitle', GameTitle, false);
this.state.add('Main', Main, false);
this.state.add('GameOver', GameOver, false);
this.state.start('Boot');
}
}
new Game();
You will see that we are importing the Main state that we created here (as well as all the others), and we are then using those imports in the this.state.add()
function.
Summary
It might feel a little bit funky at first, but if you’re already familiar with Phaser it should be reasonably easy to get started with ES6. Once you do get the hang of it, I’ll bet that you never want to go back to ES5 again.
I’ll be releasing some more tutorials based on this template in the near future so keep a look out for those!