Unity Resource: GameObjectPool

Unity LogoOne way to improve a game’s performance in Unity3D is to avoid creating and destroying game objects, and instead activating/deactivating them. However, doing so can be a bit tricky and time consuming—especially if there isn’t a hard limit on the number of game objects that can be active at any given time, and/or their lifetimes are unpredictable.

Below is a pool class I developed for use in my games. Here’s a rundown of its features.

  • It allows you to pre-instantiate a specific number of prefab instances.
  • It dynamically grows if you end up needing more objects than you originally allocated.
  • It allows objects to be spawned/unspawned in any order (in other words, it doesn’t assume that the objects spawned first will go back into the pool before objects spawned later).
  • It doesn’t require any special scripts to be attached to the objects it contains. They only need to use the built-in OnEnable/OnDisable functions to do their initialization and cleanup.

I hope you find it useful. Feel free to use/tweak/retool for your own purposes.

UPDATE: At the request of a reader, I created a little example of the pool in action. (Click here to download the project zip.) If you click the Spawn button fast enough, you should see the pool dynamically grow to accommodate more balls.

Here’s the code for the pool used in the above example.

GameObjectPool.js

#pragma strict

// A general pool object for reusable game objects.
//
// It supports spawning and unspawning game objects that are
// instantiated from a common prefab. Can be used preallocate
// objects to avoid calls to Instantiate during gameplay. Can
// also create objects on demand (which it does if no objects
// are available in the pool).
class GameObjectPool {
	// The prefab that the game objects will be instantiated from.
	private var prefab : GameObject;
	// The list of available game objects (initially empty by default).
	private var available : Stack;
	// The list of all game objects created thus far (used for efficiently
	// unspawning all of them at once, see UnspawnAll).
	private var all : ArrayList;

	// An optional function that will be called whenever a new object is instantiated.
	// The newly instantiated object is passed to it, which allows users of the pool
	// to do custom initialization.
	private var initializationFunction : Function;
	// Indicates whether the pool's game objects should be activated/deactivated
	// recursively (i.e. the game object and all its children) or non-recursively (just the
	// game object).
	private var setActiveRecursively : boolean;

	// Creates a pool.
	// The initialCapacity is used to initialize the .NET collections, and determines
	// how much space they pre-allocate behind the scenes. It does not pre-populate the
	// collection with game objects. For that, see the PrePopulate function.
	// If an initialCapacity that is <= to zero is provided, the pool uses the default
	// initial capacities of its internal .NET collections.
	function GameObjectPool(prefab : GameObject, initialCapacity : int, initializationFunction : Function, setActiveRecursively : boolean){
		this.prefab = prefab;
		if(initialCapacity > 0){
			this.available = Stack(initialCapacity);
			this.all = ArrayList(initialCapacity);
		} else {
			// Use the .NET defaults
			this.available = Stack();
			this.all = ArrayList();
		}
		this.initializationFunction = initializationFunction;
		this.setActiveRecursively = setActiveRecursively;
	}

	// Spawn a game object with the specified position/rotation.
	function Spawn(position : Vector3, rotation : Quaternion) : GameObject {
		var result : GameObject;

		if(available.Count == 0){
			// Create an object and initialize it.
			result = GameObject.Instantiate(prefab, position, rotation) as GameObject;
			if(initializationFunction != null){
				initializationFunction(result);
			}
			// Keep track of it.
			all.Add(result);
		} else {
			result = available.Pop() as GameObject;
			// Get the result's transform and reuse for efficiency.
			// Calling gameObject.transform is expensive.
			var resultTrans = result.transform;
			resultTrans.position = position;
			resultTrans.rotation = rotation;

			this.SetActive(result, true);
		}
		return result;
	}

	// Unspawn the provided game object.
	// The function is idempotent. Calling it more than once for the same game object is
	// safe, since it first checks to see if the provided object is already unspawned.
	// Returns true if the unspawn succeeded, false if the object was already unspawned.
	function Unspawn(obj : GameObject) : boolean {
		if(!available.Contains(obj)){ // Make sure we don't insert it twice.
			available.Push(obj);
			this.SetActive(obj, false);
			return true; // Object inserted back in stack.
		}
		return false; // Object already in stack.
	}

	// Pre-populates the pool with the provided number of game objects.
	function PrePopulate(count : int){
		var array : GameObject[] = new GameObject[count];
		for(var i = 0; i < count; i++){
			array[i] = Spawn(Vector3.zero, Quaternion.identity);
			this.SetActive(array[i], false);
		}
		for(var j = 0; j < count; j++){
			Unspawn(array[j]);
		}
	}

	// Unspawns all the game objects created by the pool.
	function UnspawnAll(){
		for(var i = 0; i < all.Count; i++){
			var obj : GameObject = all[i] as GameObject;
			if(obj.active)
				Unspawn(obj);
		}
	}

	// Unspawns all the game objects and clears the pool.
	function Clear(){
		UnspawnAll();
		available.Clear();
		all.Clear();
	}

	// Returns the number of active objects.
	function GetActiveCount() : int {
		return all.Count - available.Count;
	}

	// Returns the number of available objects.
	function GetAvailableCount() : int {
		return available.Count;
	}

	// Returns the prefab being used by this pool.
	function GetPrefab() : GameObject {
		return prefab;
	}

	// Applies the provided function to some or all of the pool's game objects.
	function ForEach(func : Function, activeOnly : boolean){
		for(var i = 0; i < all.Count; i++){
			var obj : GameObject = all[i] as GameObject;
			if(!activeOnly || obj.active){
				func(obj);
			}
		}
	}

	// Activates or deactivates the provided game object using the method
	// specified by the setActiveRecursively flag.
	private function SetActive(obj : GameObject, val : boolean){
		if(setActiveRecursively)
			obj.SetActiveRecursively(val);
		else
			obj.active = val;
	}
}
Advertisements

36 thoughts on “Unity Resource: GameObjectPool

  1. To handle child objects, simply pass true instead of false for the setActiveRecursively parameter (the last parameter in the GameObjectPool constructor). That will ensure that all child objects get activated/deactivated.

    If you don’t have child objects, setting active directly is faster.

  2. Hey, great piece of work. However, it should be noted that this can be detrimental to performance (in some cases) due to how it uses arrays and constant Y axis checking.

    For example, if you have 8-10 different prefabs you want to spawn/ unspawn quite often and have multiple instances of each on the screen at one time. I found that pooling all of them will make a visible dent in performance versus instantiating/ destroying them.

    1. Hmmm…the Y axis checking isn’t related to the use of pools, but it’s possible that Instantiating/Destroying could be faster than using a pool in certain cases. In Langman, I pool/unpool hundreds of objects in a single frame when a new level is loaded, and there isn’t a noticeable lag. Can you provide an example project showing the perf hit?

  3. Sure, I’ll drop a comment with a test project when i get the time (100 yard release dash right now). Dunno how visible this perf. hit would be on modern systems but I’ve tried this with one of my iPhone projects.

    The project was already maxing the iPhone’s limited resources (while still running at ~30fps). When testing the object pool, the frame rate dropped bellow tolerable.

  4. Ehren,

    This is wonderful and greatly appreciated! Thanks for posting and sharing.

    I implemented it with no problems at all.

    Any chance you might provide a C# version?

    Thanks
    Allan

  5. Ehren,

    I also noticed you use SendMessage in InitializeGameObject in CentralController.js.

    According to the Unity Community wiki, this should be avoided for iPhone development and replaced by a direct method call.

    Here is what the wiki says and the link:
    “Avoid SendMessage() calls, create a script/class variable to hold a reference to the specific scripts you want to call, and use a standard method call. Method calls are ~100x faster than SendMessage()!”

    http://www.unifycommunity.com/wiki/index.php?title=IPhone_Optimization_Tips

    Would love to see a C# version.

    Allan

  6. @Azzogat: One thing I forgot to mention is that for iPhone, you might want to try Spawning and then Unspawning the number of game objects you think you’ll need up front (in Start). That way you’ll take the hit for creating them once, which should make the spawning during gameplay faster.

    @Chaneya: The SendMessage in the example could be replaced with a GetComponent call, but that’s also slow. Because the initialization function is only called when a pooled object is created, you only take the SendMessage hit once per pooled object. If you Spawn/Unspawn all your game objects up front (in Start), you can take the perf hit for all objects before your game begins. I don’t think the iPhone guidance means you should never call SendMessage, just that you should call it sparingly (or refactor to avoid it when possible).

  7. Ehren,

    That’s a very good point regarding SendMesssage. I agree….I think the idea is to not use it per frame in say…the Update loop.

    I took the liberty of attempting to convert your code to C# but I am stuck on InitializationFunction in GameObjectPool.js. and one function in CentralController.js. I think I have everything else converted. I have a few years of experience in C# but no history in Unity/Javascript at all.

    The first issue is that C# does not have a Function Type to replace.
    And I’ve never seen a procedure/method declared as a variable type in C#.

    In GameObjectPool.js, At the top:
    private var initializationFunction : Function;
    (This appears to declare a method as a Function declaration.)??

    function GameObjectPool() receives initializationFunction : Function in its constructor and makes it equal to the declaration at the top.
    this.initializationFunction = intializationFunction;
    I have no idea how to convert this to C#.

    function ForEach() also receives func : Function in its constructor and then uses a foreach loop to cycle through the objects in the array.
    Again Function has me baffled.

    In CentralController.js:
    function Awake() instantiates the ballPool calling the function InitializeGameObject in it’s contructor. Calling a procedure/method from the Awake constructor. Again, no idea how to convert to C#.

    Any tips for these two items?

    Thanks
    Allan

  8. I converted your script to C# and it works very nicely.

    You can download it here: http://download.mediamonkey.nl/GameObjectPool.cs

    Example:

    public GameObject ballPrefab;
    protected GameObjectPool ammoPool;
    protected Transform spawnPoint;

    void Start() {
    ammoPool = new GameObjectPool(ballPrefab, 5, initBallAction, false);
    spawnPoint = transform.Find(“spawnPoint”); // just an empty gameobject as locator
    }

    void Update() {
    if (Input.getMouseButtonDown(0)) fire();
    }

    void fire() {
    GameObject ball = ammoPool.spawn(spawnPoint.position, spawnPoint.rotation);
    ball.rigidbody.velocity = transform.up * 20f;
    }

    void initBallAction(GameObject target) {
    Debug.Log(“ball created”);
    // set pool to the AutoDestruct behavior so the ball can return to it on destuction
    AutoDestruct ad = target.GetComponent();
    if (ad) ad.pool = ammoPool;
    }

    1. What’s the AutoDestruct ad = target.GetComponent(); ???
      It is giving me an error when using it. Do I need to include something or is it a function you didn’t put up??

      1. Hi Willie,

        The post contained more code, but the site interpreted it as html and removed it.
        AutoDestruct ad = target.GetComponent();
        should’ve been:
        AutoDestruct ad = target.GetComponent ();

        It is a script that automatically removes the object after a certain amount of time.
        I probably should’ve included the code, but it seemed as a no-brainer to me.
        In the initBallAction method I assign the correct pool to the script.
        When the audodestruction is triggered, it destroys the gameobject by placing it back into the pool.

        You can download the script here: http://download.mediamonkey.nl/source/AutoDestruct.cs

        With regards,
        Bart

      2. You ended up typing the same thing twice with regard to the autodestruct. I imagine you meant to type in a parameter for the get component the second time.
        Also in the code you linked your destroy is capitalized where it should be lowercase.

      3. Ah yes, the site swallowed the code again.
        I meant to type GetComponent < AutoDestruct > ()
        Replace the escaped codes with the correct characters.

        About the capitalization: in C# methods are in caps. It takes some getting used to it 🙂 But when everyone is coding like that it is considered the norm, so I’ll just follow along.

        So remember: from now on write your methods in C# with an uppercase first character.

  9. Perfect! Just what I need. I was getting a lot of lag from calling Instantiate in my game. This may be the solution I’m looking for.

    With your permission, and with all credit due, I’d like to port this over to C# and post this up on my blog so my readers can benefit from this as well. As I said before, I’ll credit you, and also link back to this page so people can see the original, if that’s all OK with you.

    1. Sure, feel free to use the code in any way you like. But you might want to check out the C# version linked in the comments above before you go through the work of porting it yourself. 🙂

  10. … ok… wordpress apparently does not like comments within <>
    here it is again…

    Hi Ehren,
    I have a question. For the below parts, I don’t follow. Am I supposed to ‘add’ my prefabs as a list? See my comments below:

    // The prefab that the game objects will be instantiated from.
    private var prefab : GameObject;

    /////am I replacing ‘prefab’ above with my own prefab object name? And do i do this for all my prefabs?

    // The list of available game objects (initially empty by default).
    private var available : Stack;

    /////Am I supposed to do something here?

    // The list of all game objects created thus far (used for efficiently
    // unspawning all of them at once, see UnspawnAll).
    private var all : ArrayList;

    /////Same here

    // An optional function that will be called whenever a new object is instantiated.
    // The newly instantiated object is passed to it, which allows users of the pool
    // to do custom initialization.
    private var initializationFunction : Function;
    // Indicates whether the pool’s game objects should be activated/deactivated
    // recursively (i.e. the game object and all its children) or non-recursively (just the
    // game object).
    private var setActiveRecursively : boolean;

    /////I’m guessing I do nothing with the above?

    Thanks so much.
    PM99

      1. Hi Ethren,
        I believe I have downloaded the sample at (http://dl.dropbox.com/u/2760522/Unity/GameObjectPool-Example.zip)

        It definitely works when I play it on it’s own. Thing is that zip has a tonne of stuff in it like libraries and folders that i’m not sure if are required to use your work.

        Ideally, I’d like to just grab the essentials of what makes your balls fall down so that I can tweak in my game (and not have inherited all the ‘extra’ that is not needed).

        Here is what I’m assuming is what is needed. If you can just clarify if that is indeed the case.
        1. BallBehaviour.js
        2. CentralController.js
        3. GameObjectPool.js
        and the ball.prefab of course.

      2. Yes, that’s all you need. Everything else is just the standard Unity assets. If I remember correctly, the only thing I’m using from the standard assets is one of the predefined PhysX materials (to make the balls bouncy).

  11. Hi @Ehren,
    I’ve opened the package and loaded the game in unity3d (3.4) and it works fine.
    Here’s my thing though. I’d like to incorporate your scripts into my game but how exactly do that? There are three scripts that appear to be the main brains:
    1. BallBehaviour.js
    2. CentralController.js
    3. GameObjectPool.js
    and the ball.prefab of course.

    Are those three scripts all that I have to worry about? Because there are a bunch of other stuff in the package.

    Really all i need is to be able to spawn those balls, but they don’t appear in my game?

    I’ve put the scripts into my /scripts folder and the ball prefab with all my other prefabs.

    Any thoughts would be most welcome.
    Thank you,
    PM99

  12. Ehren,

    My gun has a script that auto-fires a projectile when the target is within a certain distance and then ejects a shell. The projectile has an attached script that instantiates particle emitter sparks on collision.

    Your example project showed spawning pooled objects by clicking a button from within the controller. Could you please tell me how to spawn (and unspawn) from scripts outside the controller?

    Your help will be greatly appreciated.

    1. Hi Jamal,

      You’ll have to call the pool code from those other objects. From your description, you probably will want to initialize each object created with a reference to the central controller script. When it’s time to unspawn an object, the object itself can then tell the central controller, “Please unspawn me”.

      Hope that helps.
      Ehren

      1. Hi Ehren,

        Ha-ha! Thanks.

        I’m a total newbie and this is what I came up with:

        var shell : GameObject;
        var shellSpawn : GameObject;
        private var controller : CentralController;

        function Awake ()
        {
        controller = GetComponent. ();
        }

        function EjectShell ()

        {
        //Instantiate(shell, shellSpawn.transform.position, shellSpawn.transform.rotation);// my working code

        controller.shellPool.Spawn(shellSpawn.transform.position, shellSpawn.transform.rotation); // my attempt
        }

        I can see the cached objects in the hierarchy but I just can’t access them.

        What’s the best way to connect to CentralController/shellPool?

        Thanks again.
        J

      2. I think you’ll want to give the spawned objects a reference to your controller (or the current script above). You can do this by passing in an initialize method that will be called whenever the pooled objects are created, and assigning a variable on the newly spawned shell.

        newShell.controller = this.controller;

        (There’s an example of using an init method in the sample project.)

        Then when the shell wants to unspawn itself, it can simply call the controller. Something like this:

        controller.UnspawnShell(this.gameObject);

  13. Hello,

    i am creating a 3D game having a character flying in the space and player need to avoid asteroids/comets/space ship/space-shuttles and all.i am doing it by instantiating and destroying these frequently.that will take lot of memory and creates problem to render the game properly.
    can any one help me and let me know how i can do ObjectPooling for them?

    Any thing will be very helpful.
    Thanks!
    Niki.j

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s