Menu
CoddyTech

Unity's ObjectPool

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 48 of 64.

Unity ships a pool, ObjectPool<T> in UnityEngine.Pool. You tell it what to do at each step with four lambdas, and it keeps the spares and the counts. This chimney puffs smoke every 0.2 seconds, and each puff goes back after a second:

using UnityEngine;
using UnityEngine.Pool;

public class Chimney : MonoBehaviour
{
    public Puff puffPrefab;
    private ObjectPool<Puff> pool;
    private float timer;

    void Awake()
    {
        pool = new ObjectPool<Puff>(
            createFunc: () => Instantiate(puffPrefab),
            actionOnGet: puff => puff.gameObject.SetActive(true),
            actionOnRelease: puff => puff.gameObject.SetActive(false),
            actionOnDestroy: puff => Destroy(puff.gameObject),
            collectionCheck: true,
            defaultCapacity: 10,
            maxSize: 20);
    }

    void Update()
    {
        timer += Time.deltaTime;
        if (timer >= 0.2f)
        {
            timer = 0f;
            Puff puff = pool.Get();
            puff.transform.position = transform.position + Vector3.up;
            puff.Launch(pool);
        }
    }
}
// Puff.cs
private IObjectPool<Puff> pool;
private float age;

public void Launch(IObjectPool<Puff> owner)
{
    pool = owner;
    age = 0f;
}

void Update()
{
    transform.Translate(0f, Time.deltaTime, 0f);
    age += Time.deltaTime;
    if (age >= 1f) pool.Release(this);
}

createFunc runs when Get finds the pool empty; actionOnGet runs on every Get and actionOnRelease on every Release. When a puff is released while maxSize spares already wait, the pool does not keep it: actionOnDestroy destroys it. defaultCapacity is only the starting size of the pool's list, so nothing is made up front. CountAll counts the puffs the pool has made and still owns, CountActive those out in the game and CountInactive the spares. Get has switched the puff on before the chimney places it, which is fine here because Puff has no OnEnable that reads its position. The puff keeps the pool as an IObjectPool<Puff>, the interface every Unity pool implements, and Launch resets its age on every use.

With collectionCheck on, releasing a puff that is already in the pool throws an InvalidOperationException: Trying to release an object that has already been released to the pool. The check runs only in the Editor, because it searches the spares on every Release; in a build the puff would sit in the pool twice and two Gets would hand out the same object. A common cause is an object that keeps running after its release and releases itself again, which is why actionOnRelease switches it off.

challenge icon

Challenge

Medium

Burst the fireworks from Unity's pool.

  1. In Launcher's Awake, make an ObjectPool<Spark>: create with Instantiate(sparkPrefab), switch on when taken, off when released, destroy the object when let go, maxSize: 5.
  2. In Update, take each spark with pool.Get() instead of Instantiate.
  3. In Return, call pool.Release(spark) instead of Destroy.

Press Play and fire a few bursts. Then Check.

Try it yourself

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;

public class Launcher : MonoBehaviour
{
    public Spark sparkPrefab;
    public int sparks = 8;

    void Awake()
    {
        // Make the pool: create, get, release and destroy, with at most 5 spare sparks
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            for (int i = 0; i < sparks; i++)
            {
                Spark spark = Instantiate(sparkPrefab);
                spark.transform.position = transform.position + Vector3.up;
                spark.Launch(Direction(i), this);
            }
        }
    }

    // A spark whose life is over
    public void Return(Spark spark)
    {
        Destroy(spark.gameObject);
    }

    // Out and up, spread evenly round the launcher
    Vector3 Direction(int i)
    {
        return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
    }
}

All lessons in Game Architecture in Unity

Practice on your own: Unity playground