Menu

First Phaser 3 Game- Lessons & Code Pt. 1

ATTENTION: This series was about the BETA version of Phaser 3! But Phaser 3 has long been released and received tons of updates.

There is a NEW series that shows you how to create games from scratch with Phaser 3! I highly suggest you check it out:

How to Create a Mobile Game from Scratch With Phaser 3


This dev blog posts series is about my first Phaser 3 game “Pixel Memory“.

The other posts in the series can be found here:
First Phaser 3 Game – Lessons & Code Pt. 2
First Phaser 3 Game – Lessons & Code Pt. 3


As already announced previously, Chase the Shadow was my last Phaser 2 game.

With the release of Phaser 3 around the corner (at the point of writing the release date is set to 12th February), I want to build all games with Phaser 3 going forward.

So I have started with a new project using Phaser 3 (Beta 20 version). Progress has been very slow in the first day because there is currently no documentation for Phaser 3.

I am using the Phaser 3 lab examples & reading the source code to figure things out. The fact that there are similarities to Phaser 2 greatly helps, of course.

Gif of an animated loading screen built in Phaser 3. First lessons learned are summarized in this post.

Project Introduction


UPDATE 25.02.2018: Phaser 3.1.2 – Scenes Passing Data
This has been fixed. Please see this post for more details, especially regarding the use of global vars.


This project will purposely be as small as possible so I don’t overwhelm myself trying to do too much while learning Phaser 3.

I want this to be a casual puzzle game playable through touch-input (or clicks for desktops). It will be a memory game with cards – something most of us know from childhood. The name is currently set to Pixel Memory.

Overview: Phaser 3 Challenges

The point of this series is to show what worked for me in Phaser 3 and share snippets of my code.

In my first day, I have come across the following challenges using Phaser3 which I want to explain in this post.

You can click on a link to scroll directly to its paragraph:

  1. Phaser 3 Config
  2. Setting Global Variables
  3. Adding Scenes
  4. Enclosing the Whole Game Object
  5. Separate Files for Scenes & Prefabs
  6. Centering & Resizing the Canvas
  7. Going Fullscreen
  8. Bitmap Text Center Origin

1. Phaser 3 Config

The first challenge I came across was booting up the app with my preferred configuration.

In Phaser 3 we pas an object to the game constructor with all the configuration properties. The most important ones are self-explanatory as you brows the lab examples.

var config = {
	// ...
};
var game = new Phaser.Game(config);

However, there are a great deal of new properties that I find really cool. One of them is the name for the game.

The parent property is the ID of the div inside which the canvas will reside in.

Here is my full config object that I passed to the game constructor:

var config = {
	type	: Phaser.AUTO,
	width	: 9  * 64,		// 576
	height	: 15 * 64,		// 960
	parent	: 'phaser-app',
	scene	: scenes,
	title	: 'PixelMemory'
};

var game = new Phaser.Game(config);

Back to overview

2. Setting Global Variables

One thing I did a lot in Phaser 2 is setting global variables, accessible from every scene (previously “state”).

If I need access to a property from many scenes, I opt for setting a global variable instead of passing them between scenes.

Moreover, passing data between states is currently bugged (see the open GitHub issue here).

Here is how I set my global variables:

game._URL	= 'http://localhost/PhaserGames/PixelMemory/'
game._USER_ID	= 0;

And here is how you can then access them from inside any scene later on:

var url		= this.sys.game._URL;
var u_id	= this.sys.game._USER_ID;

Back to overview

3. Adding Scenes

In Phaser 3 we add an array of scenes to the scenes property of the config object.

While I love the fact that we can pass an array, I found it confusing at first because I wasn’t sure if the order I’m adding them is relevant or not.

Moreover, it’s not very readable if you have a lot of scenes to add.

To remedy this, I am adding scenes like this:

var scenes = [];

scenes.push(BootScene);
scenes.push(PreloadScene);
scenes.push(IntroScene);

var config = {
	// ...
	scene	: scenes,
	// ...
};

The order doesn’t matter besides the first scene you add.

By default, the app will automatically start with the first scene you have added to this array. However, you can also manually start the app from any scene you want.

After the first one it doesn’t matter in which order you add the scenes.

Back to overview

4. Enclosing the Whole Game Object

Unlike native apps, browser games are heavily exposed to the client.

I like to hide as much as possible in enclosed functions and make it at least harder for anyone trying to change the game at run-time (aka “hack” it).

For this reason, I have always enclosed the whole game object. I don’t know how much protection it really brings but from what I’ve read about the topic it’s better than nothing.

I believe making efforts here shows the players you care about your app. (I always try to see how easily I can hack a HTML5 game at runtime – and I feel like I can’t be the only one. Not all of them are devs but some are.)

Anyways, enclosing it was easy as I can do it pretty much the same way I did in Phaser 2:

var App = function() {};

App.prototype.start = function()
{
	// Scenes
	var scenes = [];
	
	scenes.push(BootScene);
	scenes.push(PreloadScene);
	scenes.push(IntroScene);
	
	// Game config
	var config = {
		type	: Phaser.AUTO,
		width	: 9  * 64,		// 576
		height	: 15 * 64,		// 960
		parent	: 'phaser-app',
		scene	: scenes,
		title	: 'PixelMemory'
	};
	
	// Create game app
	var game = new Phaser.Game(config);
	
	// Globals
	game._URL = 'http://localhost/PhaserGames/PixelMemory/';	// this.sys.game._URL
	game._USER_ID = 0;
	
	game._CONFIG = config;
};

window.onload = function()
{
	'use strict';
	
	var app = new App();

	app.start();
}

Back to overview

5. Separate Files for Scenes & Prefabs

For organizational reasons (and personal preference I guess), I like to have separate files for each scene & prefab.

Closure & prototyping help me keep a clean namespace. Furthermore, I focus better on the task in front of me if my code is neatly organized in files like that.

From what I understood in the lab examples, it is better to use static methods in a scene instead of prototyping them.

The string that you pass to the scene constructor is the scene’s name that you will reference when starting it (or switching to it, which is now possible in Phaser 3).

This is how I organize my scenes now:

var PreloadScene= new Phaser.Scene('Preload');

PreloadScene.preload = function()
{
	'use strict';
	
	// ...
};

PreloadScene.create= function()
{
	'use strict';
	
	// ...
};

PreloadScene.update= function()
{
	'use strict';
	
	// ...
};

And this is how I organize my prefabs:

var Helper = function() {};

Helper.prototype.createText = function(ctx, x, y, string, size, anchor)
{
	'use strict';
};

This is how you start a new scene (from within your current scene):

this.scene.start('Preload');

Back to overview

6. Centering & Resizing the Canvas

In Phaser 2 we had handy methods available to configure the position & resizing of the canvas element.

In Phaser 3 these don’t seem to be available, yet. So I had to do it old-school with CSS & native JS inside my index.html file.

For this game I want the canvas to be centered on the screen at all times and re-size together with the browser window. And it must work on mobile, as well.

Here is my CSS code (notice the ID “phaser-app” is the divfrom the parent property in the config object above):

body {
	margin: 0;
	overflow: hidden;
	background-color: black;
}
		
canvas {
	height: 100%;
}
		
#phaser-app {
	margin: 0 auto;
}

And here is my JS code:

// Resize
function resizeApp()
{
	var div = document.getElementById('phaser-app');
			
	div.style.width = window.innerHeight * 0.6;
	div.style.height = window.innerHeight;
}
		
window.addEventListener('resize', function(e)
{
	resizeApp();
});
		
resizeApp();

Back to overview

7. Going Fullscreen

In Phaser 2 we also had a handy method available to launch the app in fullscreen.

This also doesn’t appear to be part of Phaser 3 Beta 20 (at least I couldn’t find it) so I had to use the Fullscreen API manually.

This code also resides in my index.html file:

// Fullscreen
function fs_status()
{
	if(document.fullscreenElement)
	{
		return true;
	}
	else if(document.webkitFullscreenElement)
	{
		return true;
	}
	else if(document.mozFullScreenElement)
	{
		return true;
	}
	else
	{
		return false;
	}
}
		
function goFullscreen()
{
	if(fs_status())
	{
		return;
	}
			
	var el = document.getElementsByTagName('canvas')[0];
	var requestFullScreen = el.requestFullscreen || el.msRequestFullscreen || el.mozRequestFullScreen || el.webkitRequestFullscreen;
			
	if(requestFullScreen)
	{
		requestFullScreen.call(el);
	}
}
		
document.getElementsByTagName('div')[0].addEventListener('click', goFullscreen);

Back to overview

8. Bitmap Text Center Origin

Currently, it is not possible to change the origin of a bitmap text object.

It works fine for images, though (I haven’t tried other objects).

In Phaser 2, it was called “anchor”. In Phaser 3 this term seems to have been dropped completely and is replaced by “origin”.

The default origin for images is now set to 0.5 (previously 0); but for bitmap texts it is still set to 0.

Here is how you set the origin for an image:

// You can chain it directly
this.add.image(0, 0, 'bg-main').setOrigin(0);

// Or you can add it later to an image object
this.bg_main.setOrigin(0);

To have bitmap texts anchored to their center, I have written up this simple helper method:

// My helper prefab
var Helper = function() {};

// Method to create a bitmap text
// I am still calling it "ancho"r instead of "origin"; old habit that will change going forward
Helper.prototype.createText = function(ctx, x, y, string, size, anchor)
{
	'use strict';
	
	var text;
	
	var font = 'supermercado';
	var size = size || 64;
	
	// Text
	text = ctx.add.bitmapText(x, y, font, string, 64);
	
	// Anchor...
	// ...center
	if(!anchor || anchor === 0.5)
	{
		text.x -= (text.width * 0.5);
		text.y -= (text.height * 0.5);
	}
	// ...1
	if(anchor === 1)
	{
		text.x -= text.width;
		text.y -= text.height;
	}
	// ...x & y different
	else if(typeof anchor == 'object')
	{
		if(anchor.x === 0.5)
		{
			text.x -= (text.width * 0.5);
		}
		if(anchor.y === 0.5)
		{
			text.y -= (text.height * 0.5);
		}
		
		if(anchor.x === 1)
		{
			text.x -= text.width;
		}
		if(anchor.y === 1)
		{
			text.y -= text.height;
		}
	}
	
	// Return
	return text;
};

Back to overview

The Ultimate Phaser 3 Guide

Everything you need to make real, polished, professional Phaser 3 games, you find it in this guide here: HTML5 Game Development Mini-Degree

I highly suggest you check it out!

4 comments

  1. Greg says:

    Thank you very much for sharing your experiences. I am hanging on every word as I attempt to learn Phaser 3 and apply good practices to my first game.

    You mentioned in section 2 there is an open issue with passing state between scenes (https://github.com/photonstorm/phaser/issues/3180). This issue was closed a few days ago. If the fact that this issue was closed changes the way you would explain passing state, would you be so kind as to update your blog to reflect how we should be passing state? It’s so very helpful to Phaser newbies like me. Thanks again for your blog series!

  2. admin says:

    Thank you Greg for pointing this out and your kind words! I’ve actually mentioned it in the second part of the series but I completely skipped it here. While I was working on Pixel Memory, I was writing along and it really shows here.

    You are completely right, of course. I did some investigating and came across interesting facts regarding passing data and the use of global vars. For easier reading, I have summarized it in this post: Phaser 3.1.2 – Scenes Passing Data.

    Thank you so much for stopping by, reading my blog, and even improving what I’ve written!

  3. Microcipcip says:

    Hi, thanks for the tutorial. Are you able to replace the tabs with spaces? The tabs are so wide that I find it difficult to follow the tutorials.

  4. admin says:

    Hi Micro, thank you for stopping by! I’ve removed the tabs in the declaration statements but kept the tabs that define the structure & indentation. I hope it’s better now!

Leave a Reply