Object Pooling in Unity | Better Programming

Using the new Unity Pooling API to optimize performance

1*9GA fGN6Sq5poOsUULNvMQ

In Unity, we know we can create a new instance of a GameObject from a Prefab by calling Instantiate() and destroy it later by calling, surprise, Destroy(). That’s fine, nothing wrong with that. This is the way.

But if we need to allocate a large number of objects and destroy them in a short period of time, that would have an impact on performance. So here it comes Object Pooling to save the day.

Object Pooling is a creational pattern that allows us to pre-instantiate a set of objects and reuse them instead of allocating and destroying them on demand

We’re going to use the new Unity Pooling API, specifically the ObjectPool class, which uses a stack to hold a collection of object instances. Since it’s a generic class, our goal is also to create a class to manage it that we can reuse.

The problem is that the type we’re going to use needs a reference to the pool, so that we can release the object when we’re done with it by calling the ObjectPool’s Release() method.

We don’t want every class to redefine the same method. The idea is instead to create a base class that derives from MonoBehaviour, holds a reference to the pool and has a base implementation for the method we’re going to use to release the object.

Since ObjectPool is an implementation of the IObjectPool interface, we’re going to use this type to hold the reference.

Program to an interface, not an implementation

Next, we’re going to create a class to manage the pool.

We’ll work with GameObject type because it’s the base class for all the entities, but our class we’ll hold a reference to a Prefab that inherits from the Poolable class we defined earlier.

To create a new ObjectPool instance, we need to define some callbacks to pass to its constructor:

  • CreatePooledItem, used to create a new instance when the pool is empty
  • OnTakeFromPool, called when the instance is taken from the pool
  • OnReturnedToPool, called when the instance is returned to the pool
  • OnDestroyPoolObject, called when the element could not be returned to the pool due to the pool reaching the maximum size

We also need to define a default capacity and a maximum size for the pool. The boolean value is for enabling collection checks.

Few things to notice here. When the object gets created, we assign the reference to the pool by getting its Poolable component. We may perform some cleanup and state resetting when the object is taken from or returned to the pool, during the object’s lifecycle within OnEnable() or OnDisable(), or delegate the task to the class responsible for spawning the object.

Now, let’s create a class that derives from Poolable and defines a projectile.

Let’s create a Prefab to attach this script to, together with a trigger collider.

In Update, we release the object when is out of camera (Boundaries is just an enum I made that holds this point) by calling the function we inherit from the Poolable class. Same thing when the projectile hits another GameObject tagged as “Enemy”.

Now we’re going to implement a simple spawner to fire the projectile. First, we need a reference to our pool, then we define an empty GameObject as a parent transform to hold all the instances we’ll fire, keeping the hierarchy clean. We set the initial position and rotation inside the Spawn function.

All we have left now is to get a reference to the SimpleSpawner component and call the Spawn() function every time we want to fire with our player.

Feel free to play

News Credit

%d bloggers like this: