Pooling in Unity
I was following a Unity tutorial about multiplayer networking and I stumbled upon the concept of Pooling for the first time. I got side tracked and went down the rabbit hole, learning lots about pooling, hash tables and more. Here’s the results of one days of research.
Pooling is used in games in situations where lots of items of the same type are being created then destroyed. Instantiating game objects and Destroying them is very inefficient. Pooling means instead of destroying objects, just deactivate the visual part of object. A list of say 200 bullets that are always there can then be recycled. When bullet is off screen, hide it, and read it to some list, so that it can be shot out again.
- It would be useful to impellent in bullet hell type games.
- Most mobile games. Object Pooling is almost required for mobile performance due to GPU vs CPU
- Self-made particle systems.
The code below is a very simple pool manager, which reuses items. Although the code is simple to understand and works, it is quite inefficient. Because we use a list, and loop through it a lot. It would be much better to use a stack to get access features like pop and push. Why a Stack and not a List? Because we’ll never need to pluck an object from the start or middle of the array. Another issue is this class only supports Gameobjects, and there can only be one per scene.
Below this paragraph is a much better pooling manager. This class holds a dictionary of all pools inside of it, meaning it can be used to create multiple pools containing different object types. If you say to spawn a object and no pool exists, one is automatically created. It will also automatically grow if no free object is available in the pool. You can also preload any amount of items into the pool. Here’s how to use it. Instead of calling Instantiate(), use this: SimplePool.Spawn(somePrefab, somePosition, someRotation); Instead of destroying an object, use this: SimplePool.Despawn(myGameObject); If desired, you can preload the pool with a number of instances: SimplePool.Preload(somePrefab, 20); This pool could be even more efficient. On the despawn method there is a GetComponent() call, which could be worked around using a HashSet of GameObject.GetInstanceID(), to look up whether the gameobject is in the pool or not. Using these to methods is preferable to the getComponent call, because they are more efficient.
[What is a HashSet
To understand why this is actually more efficient I had to look up what a hash set was. This website above has some great info
“In C# programming, collections like ArrayList, List, simply adds values in it without checking any duplication. To avoid such a duplicate data store, .NET provides a collection name set. This is a collection type with distinct items. There are two types of sets, SortedSet and HastSet. The SortedSet stores data in sorted order and also eliminates duplication.” So basically A HashSet works like a list, but doesn’t allow duplication. Here are some interesting differences between the two Checking performance of operations like Add, Remove, Contains
List Vs Hash: ADD
List Vs Hash Contains
List Vs Hash Remove
Conclusion
HashSets are faster in almost everything except for add. List add things faster, because before add HashSets adds it needs to check for duplicates. Lists do Not. Basically A HashSet is better if you will not be adding lots of things to the collection. Things like ‘Contains’ are much better on a Hash Set because, instead of looping over the entire contents of the collection and checking equality. C# instead calculates an index based off the hashcode. So all it has to do is take that hashcode, calculate the index (a quick arithmetic process) and then look in that slot for the object (there’s a little more to it… but it’s still not looping over the entire collection).
What is the point of GetInstanceID
Next I needed to understand what was the GetInstanceID function. First thing that seemed confusing to me, was after getting the InstanceID. You cant do much with it. There is no function FindGameobjectWithID(id); So I did some research to better understand it.
So why does GameObject.GetInstanceID() exist, if you cant use it for searches? Well, it was created probably only for debugging. For example, you believe that two object references (let’s call them A and B) refer to the same object, but you’re not sure, because you have a hundred objects of the same type that are easy to get confused. So you Debug.Log the GetInstanceID of each one, and if they’re the same, then A and B refer to the exact same object. If they’re different, then they do not.
Using HashSets with GetInstanceID
To build your own collection of objects put the IDS in in HashSets, or Dictionarys. This could be used in more than one situation, Pooling being one. Another place to use this would be when you have to come up with your own identification system, using IDs handed out by some authoritative server (which could be one of the clients in a peer-to-peer game).
The following code is a small correction of quill18s.
Best Pooler So FarTheres a even better one here too but its a bit more complex. Theres a explanation from the owner on this site