Unity3D Game Object Pool Manager

I talked previously how much a game object manager improved performance in Cairn, and I want to make sure anyone using Unity has the opportunity to use it in their game as well.

When I started researching a work around for Unitys Spawn & Destroy methods I came across a large number of pre-existing solutions. ┬áThere are free scripts and expensive packages that could handle the issue, but I wanted the best of both. ┬áSomething easy to use, something I can understand, and something free. This ment we had to grow our own solution, but I didn’t have to start from scratch.

I found a great script on the Von Lehe Creative Blog. They had a great object manager, but you needed a separate script for each object you wished to pool and it was written in javascript.

Since the rest of Cairn is in C# I converted the script to that language. This allowed me to walk through the script and get a better handle on what it was doing.

Overall it’s pretty simple. Build a stack of Game Objects, mark them as active or inactive, then when something requests a new object determine if one needs to be created or if one needs to be reused.

I changed it handle more like the built Spawn & Destroy functions within Unity. The new script takes in a prefab, using it’s name to create a Game Object Pool for that specific prefab, and handles the stack of objects as the original script did from there.

You’ll notice some string manipulation and comparison that could be improved or edited, but for what I was trying to accomplish it works like a charm.

The script is below, so enjoy!

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

public class GameObjectPoolManager {

private static List _PoolObjectList = new List();

public static PoolObjectModel AddNewPoolObject(GameObject prefab, uint initialCapacity)
{
PoolObjectModel newPoolObject = new PoolObjectModel();

newPoolObject.Prefab = prefab;
newPoolObject.PrefabName = prefab.name + “(Clone)”;
newPoolObject.All = (initialCapacity > 0) ? new ArrayList((int) initialCapacity) : new ArrayList();
newPoolObject.Available = (initialCapacity > 0) ? new Stack((int) initialCapacity) : new Stack();

_PoolObjectList.Add(newPoolObject);

return newPoolObject;
}

public static int numActive (GameObject prefab)
{
PoolObjectModel poolObject = GetPoolObjectByPrefab(prefab);

if(poolObject == null)
return 0;
else
return poolObject.All.Count – poolObject.Available.Count;
}

public static int numAvailable (GameObject prefab)
{
PoolObjectModel poolObject = GetPoolObjectByPrefab(prefab);

if(poolObject == null)
return 0;
else
return poolObject.Available.Count;
}

public static GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation)
{
GameObject result;
PoolObjectModel currentPoolObject = new PoolObjectModel();

if(DoesPoolObjectExist(prefab))
{
currentPoolObject = GetPoolObjectByPrefab(prefab);
//Debug.Log(“Old Pool ” + currentPoolObject.PrefabName );
}
else
{
currentPoolObject = AddNewPoolObject(prefab, 3);
//Debug.Log(“New Pool ” + currentPoolObject.PrefabName);
}

if (currentPoolObject.Available.Count == 0)
{
// create an object and initialize it.
//Debug.Log(“Instantiate new object” + currentPoolObject.PrefabName);
result = GameObject.Instantiate(prefab, position, rotation) as GameObject;

currentPoolObject.All.Add(result);

}
else
{
//Debug.Log(“Reuse Old object” + currentPoolObject.PrefabName);
result = currentPoolObject.Available.Pop() as GameObject;

// get the result’s transform and reuse for efficiency.
// calling gameObject.transform is expensive.
if(result == null)
{
result = GameObject.Instantiate(prefab, position, rotation) as GameObject;
}

Transform resultTrans = result.transform;
resultTrans.position = position;
resultTrans.rotation = rotation;

SetActive(result, true);

//Debug.Log(“Is Active: ” + result.active);
}

return result;
}

public static bool Destroy(GameObject target)
{
PoolObjectModel currentPoolObject = GetPoolObjectByPrefab(target);

if(DoesPoolObjectExist(target))
{
if (!currentPoolObject.Available.Contains(target))
{
currentPoolObject.Available.Push(target);

SetActive(target, false);
//Debug.Log(“Is Active: ” + target.active);
return true;
}
}
else
{
Destroy(target);
return true;
}

return false;
}

public static void DestroyAll()
{
foreach(PoolObjectModel poolObject in _PoolObjectList)
{
for (int i=0; i<poolObject.All.Count; i++)
{
GameObject target = poolObject.All[i] as GameObject;

if (target.active)
Destroy(target);
}
}
}

// Unspawns all the game objects and clears the pool.
public static void Clear() {
DestroyAll();
foreach(PoolObjectModel poolObject in _PoolObjectList)
{
poolObject.Available.Clear();
poolObject.All.Clear();
}
}

public static bool DoesPoolObjectExist(GameObject prefabObject)
{
bool prefabExists = false;
string prefabName;

if(prefabObject.name.Contains(“(Clone)”))
prefabName = prefabObject.name;
else
prefabName = prefabObject.name + “(Clone)”;

foreach(PoolObjectModel poolObject in _PoolObjectList)
{
if ( poolObject.PrefabName == prefabName)
prefabExists = true;
}

return prefabExists;
}

protected static void SetActive(GameObject target, bool active)
{

RecursiveDeepActivation(target.transform, active);

}

protected static PoolObjectModel GetPoolObjectByPrefab(GameObject prefabObject)
{
string prefabName;

if(prefabObject.name.Contains(“(Clone)”))
prefabName = prefabObject.name;
else
prefabName = prefabObject.name + “(Clone)”;

PoolObjectModel poolObjectToReturn = new PoolObjectModel();
foreach(PoolObjectModel poolObject in _PoolObjectList)
{
if ( poolObject.PrefabName == prefabName)
poolObjectToReturn = poolObject;
}

return poolObjectToReturn;
}

protected static void RecursiveDeepActivation(Transform gameObjectTransform, bool activate)
{
foreach (Transform t in gameObjectTransform)
{
RecursiveDeepActivation (t, activate);
}
gameObjectTransform.gameObject.active = activate;
}
}

3 thoughts on “Unity3D Game Object Pool Manager

  1. Hi I was wondering where is this PoolObjectModel you are referring to in the script? Is this another piece of code you wrote for the script?
    I would like to use this script for my own game which is having some performance issues due to the instantiating / destroying problem.

    Thanks for getting back to me!

    • The Script would be the Game Object Pool. You would just create a .cs file and name it GameObjectPoolManager. After that you just copy and paste all of the above code into that script.

      Once the script is in place all you have to do is call it whenever you want to Instantiate or Destroy and object instead of directly using the Unity functions.

      GameObjectPoolManager.Spawn(yourGameObject); //This will instantiate your object if one does not exist or reuse an old one if it can

      GameObjectPoolManager.Destroy(yourGameObject); //This will deactivate your game object and save it for later use.

  2. Hi and thank you for the code!

    I have some problems making it work i get these 3 errors when trying to save it inside of Unitys c# script.

    Assets/Managers/GameObjectPoolManager.cs(8,24): error CS0246: The type or namespace name `List’ could not be found. Are you missing a using directive or an assembly reference?

    Assets/Managers/GameObjectPoolManager.cs(10,23): error CS0246: The type or namespace name `PoolObjectModel’ could not be found. Are you missing a using directive or an assembly reference?

    Assets/Managers/GameObjectPoolManager.cs(167,26): error CS0246: The type or namespace name `PoolObjectModel’ could not be found. Are you missing a using directive or an assembly reference?

    There were some other formatting errors when copying and pasting but i corrected them. Please help with explanation, or put a code as cs file so that others dont have the same issues.
    Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>