Question about the new built-in ObjectPooling

Greetings Unity Devs,

I have been using my own homebrew Object Pooling system in all my games and it works really well for me. It’s truly generic so I can spawn/despawn objects of any type using GameObject prefabs.

For example:

public class Launcher : MonoBehavior
{
    [SerializeField] Projectile _projectilePrefab;

   public void Fire()
    {
            GameObject projectileGameObject = ObjectPooler.Instance.SpawnGameObject(
                projectilePrefab, startPosition, rotation);
    }

}

In this example I can swap out any type of projectile type I want and it will work.

Under the covers my pooling system using a dictionary to map a string (the prefab name) to a Queue for the prefab I want to instantiate.

For example:

   public class ObjectPooler : MonoBehaviour
    {
        private static ObjectPooler Instance;
        private readonly Dictionary<string, Queue<GameObject>> _pool = new Dictionary<string, Queue<GameObject>>();
}

When I try to spawn an object from the pool, if no pool for that prefab exists I create one and if the pool doesn’t contain an object of that type, I instantiate one.

        public static GameObject SpawnGameObject(GameObject prefab, Vector3 position, Quaternion rotation, bool setActive = true)
        {
            if (Instance == null) return null;
            GameObject go = Instance.DequeGameObject(prefab);
            if (go != null)
            {
                go.transform.position = position;
                go.transform.rotation = rotation;
                go.SetActive(setActive);
            }
            else
            {
                go = Instance.InstantiateGameObject(prefab, position, rotation, setActive);
            }

            return go;
        }

        private GameObject DequeGameObject(GameObject prefab)
        {
            var pool = GetPool(prefab);
            if (pool.Count < 1) return null;
            GameObject go = pool.Dequeue();
            if (go == null)
            {
                Debug.LogWarning("Dequeued null gameObject (" + prefab.name + ") from pool.");
            }

            return go;
        }

        private Queue<GameObject> GetPool(GameObject prefab)
        {
            Queue<GameObject> pool;

            if (_pool.ContainsKey(prefab.BaseName()))
            {
                pool = _queue[prefab.BaseName()];
            }
            else
            {
                pool = new Queue<GameObject>();
                _pool.Add(prefab.BaseName(), pool);
            }
            return pool;
        }

BaseName() is just an extension method that will strip “(Clone)” from the prefab name.

When I despawn and object I just deactivate it and add it to the corresponding pool.

        public static void DespawnGameObject(GameObject go)
        {
            if (go == null) return;
            go.SetActive(false);
            var pool = Instance.GetPool(go);
            pool.Enqueue(go);
        }

Like I said, this system works great for me and the beauty of it is that it’s totally generic.

When I saw that Unity was including a built-in pooling system I thought “Great! I can swap out theirs for mine” but when I actually tried to use it I noticed that even though they use generics, the way they implemented it doesn’t support a generic approach like I use (unless I’m missing something obvious, hence my post to ask this question).

It seems to me that Unity’s ObjectPooler requires you to know up front what type of object you want to instantiate. For example, in the example provided in the documentation they use new ObjectPooler() for their pool. Furthermore, when you create a pool you specify call-back methods to create an object, return an object to the pool, destroy and object, etc. The IObjectPooler.Get() method will call your CreateFunc() but that function takes no parameters and I see no way for it to actually know what type of gameobject to instantiate. In their example they create a new GameObject() and add a ParticleSystem component to it. In other words, the CreateFunc is not agnostic of the prefab type, it assumes you are creating a particle system.

So it would seem that I’d need to create an ObjectPooler class for every type of prefab I’d want to use where it explicitly creates a pool for that type and then I’d have to maintain a dictionary or something my own object pool manager to provide the right pool for the prefab I’m spawning.

Based on that, I can’t think of a use case in which I would prefer that approach to my homebrewed system.

Am I missing something? I’d love to hear thoughts from the community on this.

If anyone is interested in using my object pooler here is a link where you can download it.

The Unity ObjectPool system is not written for GameObjects/Prefabs, it’s a pure C# object pool that can be used for GameObjects but is not the primary purpose. It has existed in the Unity source code across several packages/areas for many years, we moved it into the core to reduce the duplication. An example is provided to show how it can be used with Prefabs however it requires an exact type, it was not designed to handle mixed types.
So for your use case, I would stick to what you already have. We have done some work looking into a GameObject specialized pool system but so far nothing is planned.

Thanks Karl, I’m happy to confirm that I wasn’t overlooking something obvious!

1 Like