Booniverse
16Mar/1254

Unity: Prefactory (A Better Pool Manager)

UPDATE: Okay, so I have to apologise to @gl33mer, as I made a mistake in my instructions! The updated instructions are below. The correct call to Spawn/Despawn does not use the PoolManager.Instance object reference, as both Spawn and Despawn are static methods, not instance methods. Sorry! Also, I've uploaded a small demo package where a sphere/cube are spawned every other second (intermittently). See blow for the link.

Prefactory_v1_0
Title: Prefactory_v1_0 (2788 clicks)
Caption: Simple object pool manager for Unity3d.
Filename: Prefactory_v1_0.zip
Size: 7 kB

At the request of fellow tweeterer @gl33mer, I've uploaded my Unity pool manager component, Prefactory v1.0. I have to confess that I haven't done a great deal of stability testing with it, but I haven't had any problems with it either (and I've used it quite extensively in tests and in the few games I've published to the blog). It's fast and flexible, and hopefully of use to others. I'm working on adding extra functionality, such as string-based construction of game entities (something which would be super handy for my next little adventure) and I'll be sure to post an update when and if one is completed.

A better set of instructions than this blathering mess of a blog post would help, too. I'll see what I can do...

For the record, Prefactory v1.0 is completely free to use however you like. You don't need to credit me or anything. I don't care if you modify it, use it commercially, or get down and dirty with it (although I would be morbidly curious about how one does that with code, exactly).

A short message letting me know you're using it in something awesome would totally make my egotistical day, but that's totally optional :)

To use Prefactory v1.0:

1. Assign the PoolObject MonoBehaviour to any GameObject/Prefab you wish to pool. For PoolObjects, the following options are available:

Prefab Name: Must be filled in, and must be unique per poolable object. This is the name that the PoolManager uses to manage the object.

Is Dynamic: If true, the PoolObject's children will NOT be cached for enabling/disabling of GameObjects and renderers. Set this to true if the PoolObject's hierarchy will change.

You can trigger a PoolObject to auto-despawn with the PoolObject.DespawnAfterSeconds(float seconds) method, or a coroutine method CRDespawnAfterSeconds(float seconds) which will yield after the object is despawned.

PoolObject.Age is a float property with the PoolObject's age in seconds since last being spawned, while PoolObject.AgeAsScalar will return a normalized 0 - 1 float for any PoolObject which has had an auto-despawn triggered.

2. Create a new GameObject and assign it the PoolManager MonoBehaviour. Drag and drop PoolObjects onto the PoolManager's inspector as shown below:

The pool settings for each PoolObject appear as a collapsible roll-out, and are as follows:

Pre-Allocate: The number of PoolObject instances to create at level load.

Allocate Block: The number of new PoolObject instances to create when the pool becomes empty.

Hard Limit: If true, the PoolManager will return null once the spawn limit has been reached.

Limit: The spawn limit when Hard Limit is on.

Cull: If true, excess PoolObjects will be destroyed.

Cull Above: Any excess PoolObjects exceeding this count when Cull is on, will be destroyed.

Cull Delay: The time between culls, in seconds.

3. To get an instance from the PoolManager:

PoolManager.Spawn("prefabName");
// or
PoolManager.Spawn(GameObject instanceOfPrefabToSpawn);

4. To despawn an instance back to the PoolManager:

PoolManager.Despawn(GameObject prefabInstanceToDespawn);

 

That's all there is to it (LOL). It's not the world's most intuitive system, but it works! So there you go @gl33mer, I hope it comes in useful. And make sure you send me a link to your game when it's done!

Comments (54) Trackbacks (3)
  1. Thank you :) works perfectly.

  2. Very cool. This is most handy on portables (iPhone, Android, Tablet etc.) where instantiation and the Garbage Collector can slow a game down to a crawl. Not any more though. :)

    A mighty thanks for this!

  3. Awesome tool, thanks so much for making it. I tried using another pool manager, it didn’t work out as well. It’ll be spawning bullets, zombies, and explosions in my soon to be released game: It’s Raining Zombies( http://itsrainingzombies.blogspot.com )

    Thanks so much again :)

  4. Hey me again, slight hiccup here. When I reload a scene (with application.loadlevel) that has instantiated pool objects, the pooled objects are all gone and there is an error that comes up. Just me?

    I can circumvent this problem by requiring the player to exit the entire app and then restart the level.

    • I have exactly the same problem. When I reload a level, there’s an exception

      ArgumentException: An element with the same key already exists in the dictionary.
      System.Collections.Generic.Dictionary`2[System.String,PrefabPool].Add (System.String key, .PrefabPool value)
      PoolManager.InitializePrefabPools () (at Assets/Managers/Prefactory/_scripts/PoolManager.cs:66)
      PoolManager.Awake () (at Assets/Managers/Prefactory/_scripts/PoolManager.cs:48)

      How can I solve this?

      • Sorry I’m only just replying, since I moved my blog I no longer get email notifications for comments.

        “How can I solve this?”

        Good question! I have no idea! It’s been too long since I’ve looked at this code, but I’ll check it out when I get a chance and get back to you.

        Do either of you have the PoolManager script added to a persistent object marked as DontDestroyOnLoad()?

        Actually, it’s probably because the PoolManager uses a static Dictionary to store the object pools. I shall update it and post a follow up comment when it’s done!

  5. Okay I’ve done a quick update, adding an event to clear the existing pools when a level is loaded. I hope it works!

  6. Ow! I feel so stupid now! I made my own Pool Manager a while ago, and now I’ve being working on a V2 version since a while, but if I had noticed your plugin (actually, I noticed it, but forgot about when I needed a pool manager) I might’ve gone with that from the beginning! :P

    Anyway, too late now, I’ll finish what I started (I’m actually shedding blood on the Editor part, so that enums are automatically created for each pool – but at least I’m taking the chance to build an internal UnityEditor helper assembly :P ).

    • Awesome! That sounds much cooler than this crappy thing :D Will you be releasing it on the asset store?

      • Your thing looks awesome! :) And yes, I’m shedding blood on the editor part (while the runtime thingies are almost complete) to make it as usable as I can (plus adding other things I wanted, after using my first Pool Manager for a while, like UnitPoolCollections – which are not exactly pools, but can be used to spawn/unspawn a single instance), so I can try and release it as my first payed plugin on the Asset Store (though there’ll be free versions for you and every other developer I know – without any obligation to use it, obviously :D ).

        By the way, a silly question. To unspawn instances I always used methods called Unspawn, while I noticed you’re using Despawn. Is that a specific/common naming for it, and as such I should change Unspawn to Despawn?

        P.S. now I’m very curious to look at your code, but I promised myself I won’t. Since I plan to sell my pool manager, subconsciously (or consciously) stealing/being-inspired by parts of your code would be bad. But since I already saw the interface, can I steal your “Pre-allocate” label (way nicer than the “Startup Instances” I was using)? :P

        • Despawn has always seemed the right word to me. Perhaps it is used elsewhere and I picked it up from another engine’s vernacular, or maybe it just popped into conversation one day and sounded right? Who knows! I think both ‘despawn’ and ‘unspawn’ would be acceptible, but ‘unspawn’ does sound a little awkward to me.

          EDIT: After a little browsing, the Unreal engine does refer to it as despawning. Take that as you will!

          As for looking at my code or using terminology that I’ve used, please, go for it. I hardly think you’re the kind of person who’d just box up someone else’s code and sell it, and at any rate, it’s not very complex so it’d be strange if we didn’t have more or less the same code in place.

          Besides, how can I say no when I know you’re going to make something better?! :D

          • Thanks Boon, you’re always so nice :)

            I’m definitely going with Despawn then, thanks for the additional infos (I was already convinced when you said it sounded awkward to you), and with stealing your “Pre-allocate” label.
            About the code, you’re right that probably we have more or less the same stuff in there, but I’m a man of principles! :D So I’ll still restrain from looking at your code at least until I finish everything, and maybe do something worse, but with a bloodshed UI :D

            P.S. I suppose you missed my direct message on Twitter a while ago. Bins developer gave me some free licenses from friends. You want one (works on Win7/8 only)?

          • Sure man that looks great! Thanks!

          • Sent you the Bins stuff as a message on Unity’s forums ;)

  7. Hey, looks great and the price tag is unbeatable.

    Going to test this right away. Thanks a lot for sharing.

  8. Hey I just upgraded to Unity 4.0 and I seem to be getting this weird error:

    NullReferenceException: Object reference not set to an instance of an object
    PoolObject.SetActive (Boolean active) (at Assets/Standard Assets/Prefactory/scripts/PoolObject.cs:156)

    On this line: foreach(GameObject go in GameObjectCache){

    I tried adding some debug.log statements, the GameObjectCache seems to be adding objects just fine. I readded the PoolObject scripts to the objects and readded them to the PoolManager. I have no idea why I would be getting a null object.

    Any ideas?

    • Sorry Jason, no idea :( I’m tied up in another project at the moment and all of my Unity stuff is buried away somewhere. If I can find some time, I’ll upgrade to 4.0 and have a go at troubleshooting this. Apologies for the late reply!

    • Hi, If u could fix that problem would be great. Tool is great but it shoud work propertly on Unity 4.0
      Great Job!

      • Honestly, I don’t think I’m likely to get around to it any time soon. I wish I could help, but I’m flat out with commitments that make scripting wishful thinking right now. Feel free to mess with the source code and change it how you like (of course). It’s not very complex, there’s a few basic classes. Best of luck!

  9. Hi,
    Unity (the ‘new’ 4) gives warnings when using pool manager in the editor, there are missing layout ‘closures’ in PoolManagerEditor.cc Ln 214:
    GUILayout.EndVertical();
    GUILayout.EndHorizontal();

    thanks for this btw!

    • No problems! I wish I could solve the bug for you, but I’m out of commission for a while unfortunately. If I can find some spare time to upgrade to 4.0 and trouble-shoot this, I’ll update the blog post with new links. Thanks for downloading, and sorry for the slow response!

  10. For those of you new to optimization (probably for mobile). I came back here to share this little tidbit from the Unity documentation which is relevant to object pools. They’re not always the more performant option.

    Here’s the quote (from here:http://docs.unity3d.com/Documentation/Manual/iphone-PracticalScriptingOptimizations.html#Object%20Pooling%20Example):

    “Why Object Pooling can be Slower

    One issue is that the creation of a pool reduces the amount of heap memory available for other purposes; so if you keep allocating memory on top of the pools you just created, you might trigger garbage collection even more often. Not only that, every collection will be slower, because the time taken for a collection increases with the number of live objects. With these issues in mind, it should be apparent that performance will suffer if you allocate pools that are too large or keep them active when the objects they contain will not be needed for some time. Furthermore, many types of objects don’t lend themselves well to object pooling. For example, the game may include spell effects that persist for a considerable time or enemies that appear in large numbers but which are only killed gradually as the game progresses. In such cases, the performance overhead of an object pool greatly outweighs the benefits and so it should not be used. ”

    Hope it’s ok I posted this here Boon. I had a feeling it could save some peoples frustrations in the longer run.

    • Thanks for the excellent response, gl33mer! Knowing when (and how, and how not) to optimise is an incredibly important skill set. This is new info to me, too, so I appreciate you sharing it!

  11. Can any one help me to call the:

    3. To get an instance from the PoolManager:

    PoolManager.Spawn(“prefabName”);
    // or
    PoolManager.Spawn(GameObject instanceOfPrefabToSpawn);
    4. To despawn an instance back to the PoolManager:

    PoolManager.Despawn(GameObject prefabInstanceToDespawn);

    in java?
    I have the 3 C# scripts form prefactry folder in the Plugins folder(will be compiled first)

    now when trying to call the

    PoolManager.Spawn(GameObject instanceOfPrefabToSpawn);
    And
    PoolManager.Despawn(GameObject prefabInstanceToDespawn);

    It gives me tese errors:
    Assets/TopdownMobile/Script/DestroyBulletNew.js(6,38): BCE0044: expecting ), found ‘instanceOfPrefabToSpawn’.

    Assets/TopdownMobile/Script/DestroyBulletNew.js(6,61): BCE0043: Unexpected token: ).

    im clueles =\ really want to use this pool script as the others give me headaches.
    (im a graphical designer not a coder :( )

    • I’m afraid I can’t help without seeing your code. Maybe you could try posting on the Unity forums, as it sounds like a problem with your script formatting. I could be wrong of course. Sorry to not be much help!

      • var lifeTime : int = 2;
        //private var csScript : PoolManager;
        //var csScript : PoolManager;

        function Awake() {
        if(lifeTime <= 0)
        Despawn();
        //csScript = this.GetComponent("PoolManager");
        //csScript = GetComponentInChildren(PoolManager);

        //Destroy(gameObject, lifeTime);
        //script = GetComponentInChildren(PoolManager);
        //script.DoSomething ();
        //PoolManager.Despawn(GameObject prefabInstanceToDespawn);
        //Despawn(GameObject prefabInstanceToDespawn);
        //}
        }

        function Despawn()
        {
        PoolManager.Despawn(gameObject);
        }

        i have no errors now,but havent tested it yet(whats comented out didnt work).

        i know the scrippts have a timer it self,but i need this working for a different reason.

        • ohh,the destroy was comented oud cuz that was part of the old code

        • Pfff so it wont despawn the prefab.

          it seems that the code PoolManager.Despawn(gameObject); doesnt do any thing? putting GameObject or this.gameobject also doesnt work.

        • oke,got it working(the despawning part) here is the code.

          private var nonsense : float = 0.0;
          var thisdoesnothign : float = 0;
          var DespawnDelay = 0.0;

          function Awake() {

          }
          function Start(){

          }
          function Update(){
          thisdoesnothign += Time.deltaTime;
          if (thisdoesnothign >= DespawnDelay){
          thisdoesnothign = 0;
          if(nonsense > 0){
          Debug.Log(“nonsense”);
          } else{

          PoolManager.Despawn(gameObject);}

          }
          }

          now i have a problem. idk how to shoot the damn thing xp.(its a bullet)
          here is the code.

          public var bulletPrefab : Transform;
          public var bulletSpeed : float = 6000;
          var ShotDelay = 5.0;
          var timer : float = 0;
          var rotateJoystick : Joystick;

          function Update(){
          if (rotateJoystick.IsFingerDown()){

          timer += Time.deltaTime;
          if (timer >= ShotDelay){
          timer = 0;
          if(!bulletPrefab || !bulletSpeed){
          Debug.Log(“[shoot] ‘bulletPrefab’ or ‘bulletSpeed’ is undefined”);
          } else{
          var bulletCreate = Instantiate(, GameObject.Find(“BSpawnPoint”).transform.position, Quaternion.identity);
          bulletCreate.rigidbody.AddForce(transform.forward * bulletSpeed);
          //PoolManager.Spawn(“Bullet”).rigidbody.AddForce(transform.forward * bulletSpeed); <—Works but does not shoot from gameobject"BSpawnPoint.
          }
          }
          }
          }
          function Spawn()
          {
          PoolManager.Spawn("Bullet");
          }

          • ** var bulletCreate = Instantiate(bulletPrefab,

            Bulletprefab was missing in the upper message.

          • These questions are outside the scope of my blog. I’m not all that clued on javascript for starters, but anything not related to the PoolManager will be better asked over at the Unity forums. Good luck!

  12. Thank you so much! I was in the middle of building my own (which I really didn’t want to do) when I found this. I am building a bullet hell shot library and this is really handy! Had it up and running in 5 minutes! Thank you and great work.

  13. You, sir, are awesome!

    Thank you for this!

  14. HI! U’re awesome! just one lil question is there a way to PoolManager.Spawn a random gameObject from PoolObjects assigned in poolManager? How can i call it.
    THANK U!

  15. I want to use it for real time and I tried a lot.
    I fixed few things and I found bug.

    On this line: foreach(GameObject go in GameObjectCache){

    What is your email?
    I will send to you this fixed version.

  16. it’s a great tool!

    how i can can manage assigning gameobjects to pool manager through script only??…
    yes using it though inspector is very easy!

    in my game, a player selects a specific kind for example (bullet) before loading scene.. i want to be able to pick a gameobject then add poolmanager in real time, then it manage the rest for me (pooling etc) for the newly added gameobject.

    thanks for the great script.

  17. Hi Boon! I’m using your pool manager and I find it very useful! I’ll show you how I used it when I’ll complete my project! =)
    Unfortunately I found a small problem which is going me mad @.@
    What method do you use to initialize your prefab already spawned? I thought that in “OnEnable” method I could reinitialize the prefab to be used everytime, but i went wrong. It seems that OnEnable has been invoked when the main parent as been activated, but all its children dont. So in my “Iinitialize” function I also deactivate (“SetActiveRecursively”) some of its children, but evidently they become active again in the next update cycle.
    I just want to know what method you use to Initialize your prefab, activating/deactivating children, resetting some animations, menage audio clips etc..
    “Start” method is invoked when the prefab is ready, and all its children are active. I’d like to know if you created a sort of “OnSpawned” method that can be called to know when my prefab is ready to be initialized.

    Thank you for your patience and sorry for my poor english =P
    I’m looking for your answers! =D

  18. Was this code ever released under a License? I see that other code you have written was released under a “MIT opensource License”, “CreativeCommons.org Attribution-Share Alike license”, and “non-exclusive license to do whatever you want with this code”. I think it would be important to specify the license for the Prefractory code for future users. Thank you!

  19. Hey thanks! this is awesome but i have a quick question, i was wondering if you can spawn a random prefab from the list. At the moment you can spawn one with the prefab name but is it possible to spawn a random prefab instead?


Leave a comment