How to implement Object Pooling in Unity

Object pooling is one of the easiest forms of optimization in Unity. Just recently we implemented the Factory Design Pattern which is related to today’s subject.

Object Pooling?

Let’s begin by explaining what Object Pooling is. So this is an optimization practice which is based on instance reusability. In Factory, we created a new instance of prefab, and later we destroyed it which is not an issue when we want to create just a few instances.

Problems start arriving when we create a lot of new instances, for example when shooting bullets from a gun, or we spawn a lot of special effects.

“What problems?” you might ask?

Without digging into much detail, you might run into troubles with memory fragmentation, which might lead to a game crash and of course performance issues as instantiating new objects is resource heavy, especially when creating a lot of new instances!

With Object Pooling, we don’t have that issue, as we create objects once and only so many as we need. It gets rid of the performance and memory issues.

Implementation

Implementation of object pooling is reasonably easy, but it might differ from what I’m presenting here. My implementation is basing on the factory design pattern with just a few extensions to it. As in the case of Factory example, I’m going to present to you two versions of the implementation.

First is just a regular with a single purpose.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Basic object pool implementation
/// </summary>
public class ObjectPool : MonoBehaviour
{
    // Reference to prefab.
    [SerializeField]
    private PoolableObject prefab;

    // References to reusable instances
    private Stack<PoolableObject> reusableInstances = new Stack<PoolableObject>();

    /// <summary>
    /// Returns instance of prefab.
    /// </summary>
    /// <returns>Instance of prefab.</returns>
    public PoolableObject GetPrefabInstance()
    {
        PoolableObject inst;
        if (reusableInstances.Count > 0)
        {
            inst = reusableInstances.Pop();
            inst.transform.SetParent(null);
            inst.gameObject.SetActive(true);
        }
        else
        {
            inst = Instantiate(prefab);
        }

        return inst;
    }

    public void ReturnToPool(PoolableObject instance)
    {
        instance.gameObject.SetActive(false);

        instance.transform.SetParent(transform);

        instance.transform.localPosition = Vector3.zero;
        instance.transform.localScale = Vector3.one;
        instance.transform.localEulerAngles = Vector3.one;

        reusableInstances.Push(instance);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Poolable object used in regular object pool.
/// </summary>
public class PoolableObject : MonoBehaviour
{
    // Pool to return object
    public ObjectPool origin;

    /// <summary>
    /// Prepares instance to use.
    /// </summary>
    public virtual void PrepareToUse()
    {
        // prepare object for use
        // you can add additional code here if you want to.
    }

    /// <summary>
    /// Returns instance to pool.
    /// </summary>
    public virtual void ReturnToPool()
    {
        // prepare object for return.
        // you can add additional code here if you want to.

        origin.ReturnToPool(this);
    }
}

As you might notice, my instance has an additional function that returns it to the pool when it’s no longer needed.

However generic implementation of object pooling is a little more complicated as it requires the use of interfaces. But besides that, it’s easy to understand πŸ˜‰

/// <summary>
/// Base interface for object pool used in poolable objects
/// </summary>
public interface IObjectPool
{
    void ReturnToPool(object instance);
}

/// <summary>
/// Generic interface with more methods for object pooling
/// </summary>
public interface IObjectPool<T> : IObjectPool where T : IPoolable
{
    T GetPrefabInstance();
    void ReturnToPool(T instance);
}
/// <summary>
/// Interface for poolable objects
/// </summary>
public interface IPoolable
{
    IObjectPool Orgin { get; set; }

    void PrepareToUse();
    void ReturnToPool();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Basic object pool implementation with generic twist
/// </summary>
public class GenericObjectPool<T> : MonoBehaviour, IObjectPool<T> where T : MonoBehaviour, IPoolable
{
    // Reference to prefab.
    [SerializeField]
    private T prefab;

    // References to reusable instances
    private Stack<T> reusableInstances = new Stack<T>();

    /// <summary>
    /// Returns instance of prefab.
    /// </summary>
    /// <returns>Instance of prefab.</returns>
    public T GetPrefabInstance()
    {
        T inst;
        // if we have object in our pool we can use them
        if (reusableInstances.Count > 0)
        {
            // get object from pool
            inst = reusableInstances.Pop();

            // remove parent
            inst.transform.SetParent(null);

            // reset position
            inst.transform.localPosition = Vector3.zero;
            inst.transform.localScale = Vector3.one;
            inst.transform.localEulerAngles = Vector3.one;

            // activate object
            inst.gameObject.SetActive(true);
        }
        // otherwise create new instance of prefab
        else
        {
            inst = Instantiate(prefab);
        }

        // set reference to pool
        inst.Orgin = this;
        // and prepare instance for use
        inst.PrepareToUse();

        return inst;
    }

    /// <summary>
    /// Returns instance to the pool.
    /// </summary>
    /// <param name="instance">Prefab instance.</param>
    public void ReturnToPool(T instance)
    {
        // disable object
        instance.gameObject.SetActive(false);

        // set parent as this object
        instance.transform.SetParent(transform);

        // reset position
        instance.transform.localPosition = Vector3.zero;
        instance.transform.localScale = Vector3.one;
        instance.transform.localEulerAngles = Vector3.one;

        // add to pool
        reusableInstances.Push(instance);
    }

    /// <summary>
    /// Returns instance to the pool.
    /// Additional check is this is correct type.
    /// </summary>
    /// <param name="instance">Instance.</param>
    public void ReturnToPool(object instance)
    {
        // if instance is of our generic type we can return it to our pool
        if (instance is T)
        {
            ReturnToPool(instance as T);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Base class for objects used in generic object pool
/// </summary>
public class GenericPoolableObject : MonoBehaviour, IPoolable
{
    // Pool to return object
    public IObjectPool Orgin { get; set; }

    /// <summary>
    /// Prepares instance to use.
    /// </summary>
    public virtual void PrepareToUse()
    {
        // prepare object for use
        // you can add additional code here if you want to.
    }

    /// <summary>
    /// Returns instance to pool.
    /// </summary>
    public virtual void ReturnToPool()
    {
        // prepare object for return.
        // you can add additional code here if you want to.

        Orgin.ReturnToPool(this);
    }
}

Fantastic! As we have both versions, now we can use them!

Example

This time we are going to attach out object pool to the spaceship and shoot lasers! We are going to use a similar object with a timeout on it and bullet spawner.

Let’s code it!

using UnityEngine;

/// <summary>
/// Object pool for prefabs of TimeoutObjects
/// </summary>
public class TimedObjectObjectPool : GenericObjectPool<TimeoutObject>
{

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Timeout object.
/// It return itself to object pool after provided timeout.
/// </summary>
[RequireComponent(typeof(Rigidbody2D))]
public class TimeoutObject : GenericPoolableObject
{
    // Time after which object will be destroyed
    [SerializeField]
    private float timeout = 2;
    // Saving enable time to calculate when to destroy itself
    private float startTime;

    // Reference to rigidbody used in spawner
    public Rigidbody2D Rigidbody { get; private set; }

    /// <summary>
    /// Unity's method called on object enable
    /// </summary>
    public override void PrepareToUse()
    {
        base.PrepareToUse();
        startTime = Time.time;

        if (!Rigidbody)
        {
            Rigidbody = GetComponent<Rigidbody2D>();
        }
    }

    /// <summary>
    /// Unity's method called every frame
    /// </summary>
    private void Update()
    {
        // Waiting for timeout
        if (Time.time - startTime > timeout)
        {
            // Returning object
            ReturnToPool();
        }
    }
}
using UnityEngine;

/// <summary>
/// Prefab spawner.
/// Component uses object pool to get prefab instance every few moments.
/// </summary>
public class PrefabTimedSpawner : MonoBehaviour
{
    // Spawn rate
    [SerializeField]
    private float spawnRatePerMinute = 30;
    // Current spawn count
    private int currentCount = 0;

    // Reference to used object pool
    [SerializeField]
    private TimedObjectObjectPool objectPool;

    /// <summary>
    /// Unity's method called every frame
    /// </summary>
    private void Update()
    {
        var targetCount = Time.time * (spawnRatePerMinute / 60);
        while (targetCount > currentCount)
        {
            // Setup prefab instace to shoot!
            var inst = objectPool.GetPrefabInstance();
            inst.transform.position = transform.position;
            inst.transform.up = -transform.up;

            inst.Rigidbody.AddForce(inst.transform.rotation * (Vector2.up * 10), ForceMode2D.Impulse);

            currentCount++;
        }
    }
}

You can notice that implementation is almost the same as with the Factory Design Pattern.

So how it’s look in Unity?

I’m shooting a ton of lasers, but you can see that thanks to object pooling I only created nine instances that are reused continuously! So much performance! πŸ€“

I hope you enjoyed this post and you found it useful. As always you can take a look at full source code available in my public repository here.

See you next time! πŸ‘¨β€πŸ’»

5 3 votes
Article Rating
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
JD Dunn
JD Dunn
2 years ago

Just wanted to say thanks for this, I had object pooling set up in my game, but I wanted to implement a generic version so I didn’t have to call GetComponent on my pooled objects if they derived from the base Spawnable class.

I managed to get it all working, except figuring out how to make ‘Spawnables’ return themselves to the object pool, without having to create circular generic T references between Spawn and Pool.

I looked all over, but no solution was as brilliant as yours, you saved my ass Kudos!

2
0
Would love your thoughts, please comment.x
()
x