Object Pooling in Unity

In this tutorial, you’ll learn how to create your own object pooler in Unity in a fun 2D shooter. By Mark Placzek.

Leave a rating/review
Save for later
Share

In this scenario, you’re outnumbered 1000 to 1. There’s no need to give the Neptunians the upper hand with unexpected memory spikes. Sound familiar? Go ahead and pull up a chair and get up to speed on Object Pooling.

In this Unity tutorial, you’ll learn:

  • All about object pooling
  • How to pool a game object
  • How to expand your object pool at runtime if necessary
  • How to extend your object pool to accommodate different objects

By the end of this tutorial, you’ll have a generic script you can readily drop into a new game. Additionally, you’ll understand how to retrofit the same script for an existing game.

Prerequisites: You’ll need to be familiar with some basic C# and how to work within Unity’s development environment. If you need some assistance getting up to speed, check out the Unity tutorials on this site.

What is Object Pooling?

Instantiate() and Destroy() are useful and necessary methods during gameplay. Each generally requires minimal CPU time.

However, for objects created during gameplay that have a short lifespan and get destroyed in vast numbers per second, the CPU needs to allocate considerably more time.

Bullets are a great example of a GameObject that you might pool.

Bullets are a great example of a GameObject that could be pooled.

Additionally, Unity uses Garbage Collection to deallocate memory that’s no longer in use. Repeated calls to Destroy() frequently trigger this task, and it has a knack for slowing down CPUs and introducing pauses to gameplay.

This behavior is critical in resource-constrained environments such as mobile devices and web builds.

Object pooling is where you pre-instantiate all the objects you’ll need at any specific moment before gameplay — for instance, during a loading screen. Instead of creating new objects and destroying old ones during gameplay, your game reuses objects from a “pool”.

NonVsPooling

Getting Started

If you don’t already have Unity 5 or newer, download it from Unity’s website.

Download the starter project, unzip and open SuperRetroShooter_Starter project in Unity — it’s a pre-built vertical scroll shooter.

Note: Credit goes to Master484, Marcus, Luis Zuno and Skorpio for the medley of art assets from OpenGameArt. The royalty-free music was from the excellent Bensound.

Feel free to have a look at some of the scripts, such as Barrier; they are generic and useful, but their explanations are beyond the scope of this tutorial.

As you work through everything, it will be helpful to see what’s happening in your game’s Hierarchy during gameplay. Therefore, I recommend that you deselect Maximize on Play in the Game Tab’s toolbar.

maximise

Click the play button to see what you have. :]

Note how there are many PlayerBullet(Clone) objects instantiated in the Hierarchy when shooting. Once they hit an enemy or leave the screen, they are destroyed.

Making matters worse is the act of collecting those randomly dropped power-ups; they fill the game’s Hierarchy with bullet clones with just a few shots and destroy them all the very next second.

Youaregoingtofixthat

In its current state, Super Retro Shooter is a “bad memory citizen”, but you’ll be the hero that gets this shooter firing on all cylinders and using resources more scrupulously.

Time to Get Your Feet Wet

Click on the Game Controller GameObject in the Hierarchy. Since this object will persist in the Scene, you’ll add your object pooler script here.

In the Inspector, click the Add Component button, and select New C# Script. Give it the name ObjectPooler.

Double-click the new script to open it in MonoDevelop, and add the following code to the class:

public static ObjectPooler SharedInstance;

void Awake() {
  SharedInstance = this;
}

Several scripts will need to access the object pool during gameplay, and public static instance allows other scripts to access it without getting a Component from a GameObject.

At the top of the script, add the following using statement:

using System.Collections.Generic;

You’ll be using a generic list to store your pooled objects. This statement gives you access to generic data structures so that you can use the List class in your script.

Note: Generic? Nobody wants to be generic! Everybody wants to be special!

In a programming language like C#, generics allow you to write code that can be used by many different types while still enforcing type safety.

Typically, you use generics when working with collections. This approach allows you to have an array that only allows one type of object, preventing you from putting a dog inside a cat array, although that could be pretty funny. :]

Speaking of lists, add the object pool list and two new public variables:

public List<GameObject> pooledObjects;
public GameObject objectToPool;
public int amountToPool;

The naming is fairly self-explanatory.

By using the Inspector in Unity, you’ll be able to specify a GameObject to pool and a number to pre-instantiate. You’ll do that in a minute.

Meanwhile, add this code to Start():

pooledObjects = new List<GameObject>();
for (int i = 0; i < amountToPool; i++) {
  GameObject obj = (GameObject)Instantiate(objectToPool);
  obj.SetActive(false); 
  pooledObjects.Add(obj);
}

The for loop will instantiate the objectToPool GameObject the specified number of times in numberToPool. Then the GameObjects are set to an inactive state before adding them to the pooledObjects list.

Go back to Unity and add the Player Bullet Prefab to the objectToPool variable in the Inspector. In the numberToPool field, type 20.

ObjectPoolSetup

Run the game again. You should now have 20 pre-instantiated bullets in the Scene with nowhere to go.

Well done! You now have an object pool. :]

Well done! You now have an object pool :]

Dipping into the Object Pool

Jump back into the ObjectPooler script and add the following new method:

public GameObject GetPooledObject() {
//1
  for (int i = 0; i < pooledObjects.Count; i++) {
//2
    if (!pooledObjects[i].activeInHierarchy) {
      return pooledObjects[i];
    }
  }
//3   
  return null;
}

The first thing to note is that this method has a GameObject return type as opposed to void. This means a script can ask for a pooled object from GetPooledObject and it'll be able to return a GameObject in response. Here's what else is happening here:

  1. This method uses a for loop to iterate through your pooledObjects list.
  2. You check to see if the item in your list is not currently active in the Scene. If it is, the loop moves to the next object in the list. If not, you exit the method and hand the inactive object to the method that called GetPooledObject.
  3. If there are currently no inactive objects, you exit the method and return nothing.

Now that you can ask the pool for an object, you need to replace your bullet instantiation and destroy code to use the object pool instead.

Player bullets are instantiated in two methods in the ShipController script.

  • Shoot()
  • ActivateScatterShotTurret()

Open the ShipController script in MonoDevelop and find the lines:

Instantiate(playerBullet, turret.transform.position, turret.transform.rotation);

Replace both instances with the following code:

GameObject bullet = ObjectPooler.SharedInstance.GetPooledObject(); 
  if (bullet != null) {
    bullet.transform.position = turret.transform.position;
    bullet.transform.rotation = turret.transform.rotation;
    bullet.SetActive(true);
  }

Note: Make sure this replacement is made in both Shoot() and ActivateScatterShotTurret() before you continue.

Previously, the methods iterated through the list of currently active turrets on the player's ship (depending on power-ups) and instantiated a player bullet at the turrets position and rotation.

You've set it to ask your ObjectPooler script for a pooled object. If one is available, it's set to the position and rotation of the turret as before, and then set to active to rain down fire upon your enemy. :]

Mark Placzek

Contributors

Mark Placzek

Author

Brian Moakley

Tech Editor, Final Pass Editor&Team Lead

Wendy L

Editor

Over 300 content creators. Join our team.