Speed is an important performance metric for games. If players have to react in realtime then the framerate is a big deal.
One common cause of framerate problems is memory allocation inside update loops.
A solution to this is to use Object Pools.
We looked at basic Object Pools in the previous article. Be sure to check that out if you are unfamiliar with using a Phaser
Group as an Object Pool.
In this article, we will expand upon the basic example with an Object Pool class.
Object Pool Class
Keeping our Object Pool logic in one place is good for reusability, readabiity, and organization.
We will be spawning crates in our
CratePool class just like we did in the basic example.
Note that the code is in TypeScript.
ICratePool interface is not strictly necessary but it is often better to program against an interface than an implementation.
If interfaces are confusing then just omit it. 😎 It is not required to understand Object Pools.
In the basic example, we talked about using
classType to specify a different type than
Phaser.GameObjects.Sprite. Line 10 is how we can do that.
maxSize property is set to
-1 which means no maximum size. You can change this value to ensure the Object Pool never gets too big.
despawn() methods are where we will add logic to properly reset instances.
Note that we create the
KEY_CRATE constant here and export it for others to use. It does not have to be here. An alternative is to put all shared constants in a separate file.
despawn() logic is very similar to what we had in the basic example.
We make sure to set the
crate to be active and visible when we spawn it. Then on despawn we set it to inactive and invisible with
In this example, it does not matter if we set the
spawn(). We put it in
despawn() but you can chose either.
Integrating with the GameObjectFactory
The pattern in Phaser is to use the
GameObjectFactory to create
GameObjects with code like
Phaser doesn't know about our
CratePool class so an alternative is to use
this.add.existing() and pass in an instance of
CratePool. This will work fine but it is not idiomatic to Phaser.
It would be nicer to be able to use code like
this.add.cratePool(). We can do this and Phaser makes it easy!
We just need to register a function with the
GameObjectFactory that creates a
CratePool instance. The exact logic in this function will vary.
Because we are subclassing the
Phaser.GameObjects.Group class we can look at what Phaser does and do the same things.
Lastly, TypeScript won't know about the new
cratePool() method and complain. We can fix that by using Declaration Merging.
Using the CratePool
CratePool is the easy part. This will look similar to the Scene from the basic example.
We create a
CratePool on line 27 and then use
despawn() on lines 64 and 74.
Not many lines were saved by the
CratePool class but you can use it in another Scene without duplicating code. 👏
You can also add logic like initializing with a starting size or what rule to use when more objects need to be created.
Initialize with Starting Size
It is a common feature of Object Pools to initialize with a set number of premade objects instead of having a lazy pool that only creates instances when necessary.
Different circumstances can benefit from each approach.
We can implement initializing with a starting size like this.
On line 9 we do a safety check to ensure that we only do this if the pool has not been initialized and some joker didn't pass in a negative number. 😭
createMultiple method on line 14 is used to create as many new instances as specified by
size. We set
false because we will not be using these instances immediately.
The method can be used in a Scene like this:
The information text should show a starting Size value of 5 opposed to 0.
Check you have a performance problem from object creation before you use Object Pools or you'll just add unnecessary complexity.
In the next article, we will look at using Object Pools with Matterjs physics bodies. Pooling simple images is more academic than practical since games are usually more complex than that!
Let us know in the comments below if anything doesn’t work or is unclear. 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.