How to Communicate Between Scenes in Phaser 3

Use events to pass data between Scenes for decoupled code

by on 4 minute read updated on


Are using modern JavaScript and splitting your Phaser 3 game code into multiple files? 👏

One common best practice is to put the UI code in a separate Scene.

But then how are you supposed to give the UI Scene information like player health or score?

How would a pause button in the UI Scene tell the Game Scene to pause?

One solution is to pass data using events.

The easiest way to implement this is to use the EventEmitter instance from this.game.events but…

Phaser docs suggest:

You should generally avoid accessing any of the systems created by Game, and instead, use those made available to you via the Phaser.Scene Systems class instead.

🤔

No problem! We can make our own EventEmitter instance to use!

It is super easy and we'll show you how in this article.

Creating an EventEmitter

Every Scene has an events property that is an EventEmitter instance local to each Scene.

It is generally used to listen for Scene events like SHUTDOWN to perform any cleanup.

Since each Scene has a local instance, it can't be used to pass data between two different Scenes.

There is an EventEmitter instance available in the Game instance but accessing this.game is generally not recommended.

You also risk emitting event names used by Phaser when you use this.game.events. This can result in undefined behavior.

Your safest bet is to make an EventEmitter instance that no one else is using.

We can do that by creating a new file named EventsCenter.js like this:

1
2
3
4
5
import Phaser from 'phaser'

const eventsCenter = new Phaser.Events.EventEmitter()

export default eventsCenter

Just 3 lines of code! It can even be turned into 2.

Now let's see how we can use it in two Scenes.

Communicating Between Two Scenes

Our example will have a simple UIScene class that can update a Text object to show a counter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import Phaser from 'phaser'

export default class UIScene extends Phaser.Scene
{
	constructor()
	{
		super('ui-scene')
	}

	create()
	{
		this.label = this.add.text(10, 10, 'Count: 0', {
			fontSize: 32
		})
	}

	updateCount(count)
	{
		this.label.text = `Count: ${count}`
	}
}

Then in our Game Scene, we update a count property each time the space key is pressed.

This is what create() looks like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// import eventsCenter 
import eventsCenter from './EventsCenter'

// then later in the Game Scene file
create()
{
	this.count = 0

	this.scene.run('ui-scene')
	
	this.input.keyboard.on('keydown-SPACE', () => {
		++this.count

		eventsCenter.emit('update-count', this.count)
	})

	this.events.once(Phaser.Scenes.Events.SHUTDOWN, () => {
		this.input.keyboard.off('keydown-SPACE')
	})
}

First, we import the eventsCenter instance on line 2.

Then we run the UIScene in parallel with the Game Scene on line 9.

The important part is line 14 where we emit an event named 'update-count' with the current value of this.count.

At this point, UIScene is not listening to any events from eventsCenter.

Let's change that by updating create() in UIScene:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// don't forget to import eventsCenter in the UIScene
import eventsCenter from './EventsCenter'

// then in create...
create()
{
	this.label = this.add.text(10, 10, 'Count: 0', {
		fontSize: 32
	})

	// listen to 'update-count' event and call `updateCount()`
	// when it fires
	eventsCenter.on('update-count', this.updateCount, this)

	// clean up when Scene is shutdown
	this.events.on(Phaser.Scenes.Events.SHUTDOWN, () => {
		eventsCenter.off('update-count', this.updateCount, this)
	})
}

Pressing the space key will trigger the count property in the Game Scene to increment and emit an event called 'update-count'.

Then the UIScene will update the Text object to show the new value of count.

It will look something like this:

Next Steps

Now you can easily create multiple Scenes that run in parallel and have them pass data to each other.

The example above just shows communication from Game to UIScene but you can just as easily pass information in the other direction for a pause button.

Be sure to sign up for our newsletter so you don't miss any future Phaser 3 game development tips and techniques!

Drop your email into the box below.

Don't miss any Phaser 3 game development content

Subscribers get exclusive tips & techniques not found on the blog!

Join our newsletter. It's free. We don't spam. Spamming is for jerks.

Phaser 3 events modern javascript

Want tips and techniques more suited for you?


You may also like...


Video Guides


Beginner Guides


Articles Recommended For You

Fix Stretched Image Distortions in Phaser 3 with 9-Slice Scaling

by on

Are you having image distortion problems when scaling to make a button or panel graphic bigger? Multiple versions of the …

5 minute read

Command Pattern to Undo Player Actions

by on

Are you looking for a clean and reusable way to implement undo for player actions? Perhaps you are making a turn-based …

15 minute read

Advanced Logging with the Strategy Pattern

by on

Have you ever tried debugging a problem with your game that only seems to happen in production? The Developer Tools …

7 minute read

State Pattern for Character Movement in Phaser 3

by on

Writing clean and well-organized code is something all game developers aspire to. We want code to be reusable and easy …

7 minute read

Didn't find what you were looking for?


comments powered by Disqus