Home

Awesome

BeauPools

Current Version: 0.3.1
Updated 12 April 2024 | Changelog

About

BeauPools is an object pooling library for Unity. It contains both generic pools and a Unity-specific prefab pool, along with utilities for managing those prefab pools.

Table of Contents

  1. Usage
  2. PrefabPool
  3. Reference

Usage

Installing BeauPools

Download BeauPools.unitypackage from the repo. Unpack it into your project.

BeauData uses the BeauPools namespace. You'll need to add the statement using BeauPools; to the top of any scripts using it.

Pool Types

There are four types of pools in BeauPools: Fixed, Dynamic, Prefab, and Serializable.

Pool TypeCapacityRequires ConstructorNotes
FixedFixed capacity. If allocating from empty pool, an exception is thrown.
DynamicDynamic capacity. If allocating from empty pool, a new element will be constructed.
PrefabDynamic pool (see above).XUnity-specific behavior documented below.
SerializableDynamic pool (see above).XSimilar functionality to Prefab pool, inspector serializable.

Creating/Destroying a Pool

public class SomeObject { ... }

// -- Creating a FixedPool --

// Max size for the FixedPool
int fixedPoolCapacity = 32;

// Constructor, required for generating pool elements
// This should return identical elements every call
// Pool.DefaultConstructor returns a default constructor for types with empty constructors
Constructor<SomeObject> someObjectConstructor = Pool.DefaultConstructor<SomeObject>();

// Strict typing
// True by default. Set this to false if you don't know
// exactly the type of object being generated by the constructor
bool fixedPoolStrictTyping = true;

// Finally, generating the pool
FixedPool<SomeObject> fixedPool = new FixedPool<SomeObject>( fixedPoolCapacity, someObjectConstructor, fixedPoolStrictTyping );

// -- Creating a DynamicPool --

// You can use more specific constructors if desired
Constructor<SomeObject> customObjectConstructor = (IPool<SomeObject> pool) => { return new SomeObject(); };

DynamicPool<SomeObject> dynamicPool = new DynamicPool<SomeObject>( 16, customObjectConstructor );

// -- Destroying a Pool ---

// To destroy a pool, call Dispose()
fixedPool.Dispose();
dynamicPool.Dispose();

Populating a Pool

By default, pools do not start with any elements. You must prewarm the pool with its initial set of elements.

// This will ensure the pool contains 16 elements
somePool.Prewarm( 16 );

// This will fill the pool up to its current capacity.
somePool.Prewarm();

You can shrink the number of elements in the pool down as well.

// This will ensure the pool contains no more than 16 elements.
somePool.Shrink( 16 );

You can also clear a pool of all its elements with Clear().

Using a Pool

To allocate an element from the pool, call Alloc(). To return it to the pool, call Free( [element] ).

// Allocate the element from the pool
var element = somePool.Alloc();

// Do something with the pooled element
...

// Return the element to the pool
somePool.Free(element);

You can also allocate and free in batches.

List<SomeObject> objectInUse = new List<SomeObject>();

// This will allocate 16 elements and add them to the list
somePool.Alloc(objectsInUse, 16);

// Do something with those elements
...

// Free them all at once
somePool.Free(objectsInUse);

Callbacks and Events

If your pooled object inherits from the IPooledObject<T> interface, it will receive certain calls from the pool during the object's lifecycle. These events are OnConstruct, OnAlloc, OnFree, and finally OnDestruct. The IPoolConstructHandler and IPoolAllocHandler interfaces also exist to provide non-generic interfaces for receiving these events, regardless of the exact pool type.

public class PooledObjectWithCallbacks : IPooledObject<PooledObjectWithCallbacks>
{
	// Called when this object is constructed for the given pool 
	public void OnConstruct(IPool<T> inPool)
    {
		...
	}
    
    // Called when the element is allocated from the pool
    public void OnAlloc()
    {
		...
	}
    
    // Called when the element is returned to the pool
    public void OnFree()
    {
		...
	}
    
    // Called when the element is destroyed from within the pool
    public void OnDestruct()
    {
    	...
    }
}

public class SomeConstructHandler : IPoolConstructHandler
{
    public void OnConstruct()
    {
        ...
    }

    public void OnDestruct()
    {
        ...
    }
}

public class SomeAllocHandler : IPoolAllocHandler
{
    public void OnAlloc()
    {
        ...
    }

    public void OnFree()
    {
        ...
    }
}

Some suggested uses for these callbacks:

Every pool also contains an PoolConfig object. This allows you to register additional callbacks on a per-pool rather than per-element basis. See PoolConfig Members below for documentation.

PrefabPool

PrefabPool Requirements

PrefabPools are pools intended for instantiating and pooling Unity prefab objects. To this end, they have the following properties.

SerializablePool

BeauPools provides the SerializablePool object for easy setup of a PrefabPool in the inspector. It can be treated as a PrefabPool, and also provides a set of methods for managing all currently allocated/active objects from the pool.

A SerializablePool operates by constructing an internal PrefabPool and performing operations on that pool. The internal pool will be constructed when Initialize is called. It will also be lazily instantiated if any Alloc or Prewarm methods are called. It will not be lazily instantiated if a Free method is called, and will error if the internal pool is not present.

Note: due to Unity's serialization rules in versions prior to 2020.1, you must create a subclass of SerializablePool for each type of component you want to pool.

// This is necessary, since Unity won't serialize generic classes
[Serializable]
public SomePooledBehaviourPool : SerializablePool<SomePooledBehaviour> { }

public class TestSerializedPool : MonoBehaviour
{
	[SerializeField]
	private SomePooledBehaviorPool myPool;
    
    private void Start()
    {
  		// Initialize can be called before the pool is used, but is not required
		myPool.Initialize();
	}
    
    private void OnDestroy()
    {
    	// Make sure to destroy your pool before it goes out of scope
    	myPool.Destroy();
    }
    
    public SomePooledBehaviour Spawn()
    {
    	// A SerializablePool can be treated like any other pool
    	return myPool.Alloc();
    }
}

Reference

Pool Members

MemberTypeDescription
CapacityPropertyCurrent capacity of the pool. In fixed pools, this is a hard limit. In dynamic pools, this is a softer limit.
CountPropertyCurrent number of elements in the pool.
InUsePropertyCurrent number of elements allocated from the pool.
ConfigPropertyEvent configuration. Use this to hook up callbacks to specific pool events.
Prewarm(int count)MethodEnsures the pool contains at least [count] number of elements.
Prewarm()MethodEnsures the pool contains up to its current capacity in elements.
Shrink(int count)MethodEnsures the pool contains no more than [count] elements.
Clear()MethodClears all elements from the pool.
Dispose()MethodClears all elements and cleans up memory used by the pool.
Alloc()MethodAllocates an element from the pool.
Alloc(T[] array)MethodAllocates elements from the pool to empty slots in the given array.
Alloc(ICollection<T> collection, int count)MethodAllocates [count] elements and adds them to the given collection.
TempAlloc()MethodAllocates an element from the pool and returns a disposable TempAlloc<T> struct that will free the element on dispose.
TryAlloc(out T element)MethodAttempts to allocate an element from the pool.
TryAlloc(T[] array)MethodAttempts to allocate elements from the pool to empty slots in the given array.
TryAlloc(ICollection<T> collection, int count)MethodAttempts to allocate [count] elements and add them to the given collection.
Free(T element)MethodReturns an element to the pool.
Free(T[] array)MethodReturns elements from the given array to the pool.
Free(ICollection<T> collection)MethodReturns elements from the given collection to the pool.
UseIDisposable()MethodHooks up the IDisposable.Dispose() call to object destruction. (Only when T inherits from IDisposable )

PoolConfig Members

MemberTypeDescription
RegisterOnConstruct(LifecycleEvent<T> callback)MethodRegisters a callback to be called when an element is constructed.
RegisterOnDestruct(LifecycleEvent<T> callback)MethodRegisters a callback to be called when an element is destroyed.
RegisterOnAlloc(LifecycleEvent<T> callback)MethodRegisters a callback to be called when an element is allocated.
RegisterOnFree(LifecycleEvent<T> callback)MethodRegisters a callback to be called when an element is freed.

PrefabPool Members

MemberTypeDescription
NamePropertyName of the pool. Used when naming prefab instances.
PoolTransformPropertyParent Transform for all inactive elements in the pool.
DefaultSpawnTransformPropertyThe default parent Transform to which allocated elements are attached.
Alloc(Transform parent)MethodAllocates a new element as a child of the given transform.
Alloc(Vector3 position, bool worldSpace)MethodAllocates a new element with the given position.
Alloc(Vector3 position, Quaternion orientation, bool worldSpace)MethodAllocates a new element with the given position and orientation.
Alloc(Vector3 position, Quaternion orientation, Transform parent, bool worldSpace)MethodAllocates a new element as a child of the given transform with the given position and orientation

SerializablePool Members

MemberTypeDescription
ConfigureCapacity(int capacity, int prewarm, bool prewarmOnInit)MethodConfigures capacity and prewarm settings.
ConfigureTransforms(Transform poolRoot, Transform spawnRoot, bool resetTransformOnAlloc)MethodConfigures transform and reset settings.
Initialize()MethodInitializes the pool.
IsInitialized()MethodReturns if the pool has been initialized.
ActiveObjectsPropertyReturns the set of currently allocated objects.
GetActiveObjects(ICollection<T>)MethodAdds the set of currently allocated objects to the given collection.
GetActiveObjects(T[])MethodAdds the set of currently allocated objects to the given array.
GetActiveObjects(T[], int)MethodAdds the set of currently allocated objects to the given array at an offset.
GetActiveObjects(List<T>)MethodAdds the set of currently allocated objects to the given array.
Reset()MethodReturns all currently allocated objects to the pool.
Destroy()MethodCalls Reset() and destroys the pool.

Misc Utilities

UtilityDescription
PooledListPooled list. Useful when you need a temporary ordered collection.
PooledSetPooled hashset. Useful when you need a temporary unordered collection.
PooledStringBuilderPooled StringBuilder. Useful when you need to temporarily concatenate strings.
TransformPoolTransform specialization of SerializablePool
SpriteRendererPoolSpriteRenderer specialization of SerializablePool
RectTransformPoolRectTransform specialization of SerializablePool
ImagePoolImage specialization of SerializablePool
TempAlloc<T>Disposable struct wrapper for a temporary allocation. Will free the allocated element on dispose.
Pool.TryFree(Component)Attempts to free the given prefab to its source PrefabPool or SerializablePool
Pool.TryFree(GameObject)Attempts to free the given prefab to its source PrefabPool or SerializablePool