Speed is often an important performance metric in a game. If players have to react in realtime then framerate is a big deal.
One common reason for framerate problems is memory allocation inside update loops.
Memory allocation happens when creating new instances.
You generally want to avoid doing that as much as you can but making things appear in response to player interaction is unavoidable.
The solution is to use Object Pools.
In this article, we will take a look at using Object Pools in Phaser 3.
What is an Object Pool?
The big idea behind an Object Pool is to create instances of objects ahead of time to reuse them later.
Instead of creating a new instance of something you would take an unused instance from the pool.
Once finished with the instance it is returned to the pool for later use.
Like recycling. ♻️
Object Pools in Phaser
Phaser 3 has Groups
that are designed to let you create, manipulate, or recycle similar GameObjects
.
While not described as an Object Pool, they have the fundamental features of an Object Pool.
Our example will look something like this:
Setting Up the Scene
We will keep all logic in a single Scene for simplicity. In the next article, we will look at encapsulating the Object Pool logic.
For now, just keep it simple. Note that the code is in TypeScript. 😎
|
|
All the code in update()
is only to show information about the state of our Object Pool.
The Group
instance that will act as our Object Pool is created on line 26.
crate.png
is an image we are using from Kenney.nl and the project structure is from the phaser3-parcel-template.
Next, let's add logic to the spawnCrate(x, y)
method on line 56 to handle spawning crates.
Creating or Reusing
The Phaser.GameObjects.Group
class has a get()
method that will create a new instance under 2 cases:
- when the group is empty
- when all member instances are active
When there are inactive instances in the group it will return the first inactive instance it finds by checking the active
property.
Let's see how we can use get()
and add a simple scale and fade tween animation to each spawned crate.
|
|
We use this.group.get()
on line 19 to get a member instance. It will be of type Phaser.GameObjects.Sprite
by default. We can change that by providing classType
when adding the group in create()
.
The next 4 lines are there to make sure the instance is properly reset because it could be a reused instance.
The active
and visible
properties need to be reset because we set them to false
at the end of the tween by calling this.group!.killAndHide(crate)
.
The alpha
and scale
properties are reset to 1 because they are changed by the tween.
Now let's use this method to see some crates!
|
|
We added lines 22 - 24 to listen to the POINTER_DOWN
event and then spawn a crate at the pointer location.
Run the Scene and you'll get something this:
The information text shows the size of the pool, the number of active instances spawned, and the number of inactive instances despawned.
You'll notice that the pool only gets bigger when there are no inactive instances to reuse.
Next Steps
That's the basics for using Object Pools with Phaser 3 Groups
.
In the next article, we will take this one step further and create an Object Pool class based on Phaser.GameObjects.Group
to keep specific spawn and despawn logic in one place.
Using the Phaser Group
is not strictly necessary and you can roll your own Object Pool implementation. Let us know in the comments below if you'd like to know more.
If anything doesn’t work or is unclear please leave it in the comments as well. We’ll be happy to fix or clarify!
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.