The ObjectPool<T>
class allows you to easily and efficiently reuse objects instead of creating and destroying them all the time, which can improve performance. It is fully generic so it can be used with any type of object such as Component
s in the scene, ScriptableObject
assets, or any other class.
Several of the Weaver examples make use of pools: Floating Text, Missiles, and Missile Command.
Basic usage of an object pool is quite simple:
- Construct a
new ObjectPool<T>
with a delegate that will be used to create new items as they are needed. You can optionally specify a number of items topreAllocate
immediately. - Call
Acquire
to get an object from the pool. - Call
Release
when you are done with the object to give it back to the pool.
Utilities and Extensions
The non-generic ObjectPool
class contains various utilities and extension methods for creating and interacting with pools:
CreateDefaultPool
returns a pool that creates new items using a the default constructor of T.CreateComponentPool
takes a prefab of anyComponent
type and returns a pool that creates new items by instantiating that prefab.GetSharedComponentPool
is similar, but it stores each pool it creates so it can return the same one if it is given the same prefab again. The examples mentioned above use this method so that each prefab with aMissile
component has its own pool of instances (same forFloatingText
andExplosion
).CreatePrefabPool
andGetSharedPrefabPool
are the same thing forGameObject
prefabs. Generally you will want a specificComponent
on the prefab though, so it's often best to use the component type directly.TryRelease
releases the item to the given pool, or returns false if the pool is null.TryReleaseOrDestroy
is similar, but callsObject.Destroy
on the item if the pool is null.TryReleaseOrDestroyGameObject
is similar, but if the object is released it'sGameObject
is automatically deactivated, or if the pool is null it callsObject.Destroy
on the component'sGameObject
(rather than only destroying the component).
By default, an ObjectPool<T>
will use a HashSet<T>
as its ActiveObjects
collection for efficiently adding and removing items, but you can give it any type of collection in the constructor and if you want to use a List<T>
in particular, you can use the PooledList<T>
class instead of ObjectPool<T>
. The non-generic PooledList
class also has similar utilities and extension methods.
Destroy or Release?
Other object pooling systems generally force you to choose whether something can be used on its own or will be pooled:
- If the object destroys itself when it's done then it can't be reused in an object pool.
- If the object deactivates itself when it's done then using it without an object pool would leave it inactive without ever reusing it, which isn't necessarily a problem but would be wasting memory at the very least.
- If the object simply indicates that it is done and relies on something else to respond accordingly, it still depends on something else and can't be used on its own.
The static ObjectPool<T>.Current
property allows you to avoid the problem. When a pool creates a new item, the pool is assigned to that property (and cleared immediately after) so that the new object can get a reference to the pool that created it in its constructor. This means the object can decide what to do when it's done based on whether it came from a pool or not.
PoolableBehaviour<T>
is a Component
class which makes use of that feature in conjunction with the ObjectPool.TryReleaseOrDestroyGameObject<T>
extension method. All of the examples mentioned above inherit from PoolableBehaviour<T>
so that while they are currently only used in object pools, you could for example have a big boss fire a custom once-off Missile
prefab without using a pool and it would still work properly.
Asset Injection
The [AssetPool]
attribute allows ObjectPool<T>
fields to have their value set by the Asset Injection system. The TextManager
class contains an example of this: each of its text types is an injected prefab the user can assign in the Weaver Window, then on startup Weaver automatically creates an ObjectPool<T>
for each of them which will instantiate their prefab to create its items.