Using Phaser in an Angular 8 Component
I have spent the last year developing HTML5/JavaScript games for my professional career as well as personal passion projects. One of my favorite tools for creating these games is Phaser (https://phaser.io).
Phaser is a powerful JavaScript library for building HTML5 games for mobile & desktop. It renders to WebGL & Canvas, and provides a lot of valuable tools: a built-in physics engine, animation & sprite support, input controllers, device scaling, etc.
Aside from inserting the Canvas or WebGL elements to run the game, Phaser stays out of the DOM and makes no effort to host or style the presentation. Luckily, there is no shortage of other tools to address these concerns.
Angular (https://angular.io) is a very popular web framework for creating robust applications for web, mobile & desktop. It uses TypeScript in later versions and handles creating an application, structuring the presentation and bundling for deployment. It is one of the most commonly used tools to create Single Page Applications (SPAs).
Phaser handles the rendering and logic of a JS game. Angular handles the presentation and structure of an application. The opportunity for integration seems natural.
Unfortunately, the actual integration is far from natural. There are slight differences in the implementation of Phaser & Angular that make integration more challenging and can initially be discouraging. These two tools can work together though, and I will show you how.
For the rest of this article, I am assuming you’ve setup NPM and are familiar with the Angular CLI.
- To learn more about NPM, please go here: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
- To learn more about Angular and the Angular CLI, please go here: https://angular.io/start
Create an Angular application
First, we need to create our Angular application using the Angular CLI. If you’re planning to incorporate Phaser into an existing Angular application, you can skip this step.
ng new phaser-angular-app
When prompted, add routing if you want and select the stylesheet format of your preference. Then, change directories into your newly created app:
cd phaser-angular-app/
Install and Copy Phaser files
Once we’re in our project directory, we want to install Phaser with npm:
npm i phaser
Then, we need to copy some files into our project to make Phaser work with Angular.
- Copy
phaser.d.ts
from the directory/node_modules/phaser/types
and paste it into your root project* folder. This provides TypeScript typings for Phaser. - Copy
phaser.min.js
from the directory/node_modules/phaser/dist
and paste it into your project’ssrc/assets
folder. This avoids the hassle of finding the correct way to constantly import Phaser into your components.
*This post has been updated to the correct folder location. Also, as noted below by Brandon, you can skip the copy steps by adding
"scripts": ["node_modules/phaser/dist/phaser.min.js"]
to the build settings in your angular.json file.
Update index.html
In your index.html
file, we need to add a static reference to the phaser.min.js
file so add this somewhere in between your <head>
tags:
<script src="assets/phaser.min.js">
Additionally, Phaser’s TypeScript typings require a global
variable, so we need a default in case this variable isn’t set elsewhere in our application.
<script>
if (global === undefined) {
var global = window;
}
</script>
Creating a game component
Next, we need to create a component to hold our Phaser game.
ng generate component game
When you navigate to your newly-created game.component.ts
file, you should see something like this:
import { Component, OnInit } from '@angular/core';@Component({
selector: 'app-game',
templateUrl: './game.component.html',
styleUrls: ['./game.component.scss']
})
export class GameComponent implements OnInit { constructor() { }
ngOnInit() {
}
}
Now, let’s add our newly created component to the landing page of our application. Open app.component.html
and delete everything (except <router-outlet></router-outlet>
if you chose to add routing). Add our new component by placing <app-game></app-game>
somewhere in this file.
When we run our application with ng serve --open
, we’ll be taken to localhost:4200
and you should see a blank page. We’ve got our app up and running!
Importing Phaser into our game component
In game.component.ts
, add the following import under the other import statements:
import Phaser from 'phaser';
If you’re using a TypeScript compiler in your IDE, TypeScript will likely complain and throw an error here: “This module is declared with using ‘export =’, and can only be used with a default import when using the ‘allowSyntheticDefaultImports’ flag.”
This error means that the Phaser module does not have a default export, and TypeScript usually does not like to let that slide. However, we can disable this warning by modifying our tsconfig.json
file.
"compilerOptions": {
"allowSyntheticDefaultImports": true,
...
}
Setting this flag to true will disable that check and allow the Phaser module to be imported. While we’re in tsconfig.json
, there’s one other change we need to make. We need to add "scripthost"
to our "lib": []
array:
"lib": [
"es2018",
"dom",
"scripthost"
]
This needs to be added because otherwise we’ll get an error later on about Phaser not being able to find ActiveXObject
.
Creating our game
Finally, we’re ready to start creating our game in our GameComponent
.
In our game.component.ts
file, we’re going to declare a new class and create our first scene.
class MainScene extends Phaser.Scene {
constructor() {
super({ key: 'main' });
} create() {
console.log('create method');
} preload() {
console.log('preload method');
} update() {
console.log('update method');
}
}
We have a scene! Now, we need to configure and create our game.
@Component({
selector: 'app-game',
templateUrl: './game.component.html',
styleUrls: ['./game.component.scss']
})
export class GameComponent implements OnInit {
phaserGame: Phaser.Game;
config: Phaser.Types.Core.GameConfig; constructor() {
this.config = {
type: Phaser.AUTO,
height: 600,
width: 800,
scene: [ MainScene ],
parent: 'gameContainer',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 100 }
}
}
};
} ngOnInit() {
this.phaserGame = new Phaser.Game(this.config);
}
}
Now that we’ve set everything up, when we run our application with ng serve —-open
, we should see a blank canvas when we access our component. Phaser has successfully integrated with our Angular app and now you can focus on building your game!
There are tons of useful tutorials on building games with Phaser, but I’d recommend sticking to TypeScript tutorials like this one or this one. Keep in mind as you follow along with these that the webpack
parts assume we aren’t bundling our Phaser game inside another app.
I have created a GitHub repository with a completed version of this tutorial. You can find it here: https://github.com/brsullivan/phaser-angular-app-step1
*A previous version of this story directed to this repository instead: https://github.com/brsullivan/phaser3-angular8. The content is similar but not an exact match to the steps in this tutorial.