A lightweight and flexible object pooling system for Unity. This project is a heavily-modified fork of uPools, featuring an entirely upgraded core pooling manager, advanced configuration options, and several new systems built on top of the original library.
πΊ Watch the full tutorial on YouTube: https://youtu.be/kooOjK0K0bk
A lightweight and highly flexible object pooling system for Unity with category support, weighted instantiation, callbacks, and advanced spawn behaviors.
Furthermore, it provides support for asynchronous object pooling using UniTask and object pooling with Addressables.
-
Heavily upgraded core pooling manager built on top of uPools
-
Scriptable Pool Configs for fully data-driven pooling setup
-
Support for multiple prefabs per pool key
-
Four instantiation modes: Sequential, Random, Weighted Random, First-Only
-
Prefab categories with automatic grouping and filtering
-
Customizable transform reset system
-
Prefab Defaults
-
Custom Defaults
-
Provided Runtime Values
-
Keep Current Transform
-
-
Advanced overflow handling
-
Block
-
Reuse Oldest
-
Reuse Random
-
-
Initial & Maximum pool size control with optional prewarm on start
-
Built-in logging tools and automatic validation for broken configs
-
Callback system with IPoolCallbackReceiver (OnRent, OnReturn, OnInitialize, OnDestroy)
- Works on root and child objects
-
Full support for uPools base features
-
Generic ObjectPool
-
SharedGameObjectPool as an Instantiate/Destroy replacement
-
UniTask async pooling
-
Addressables pooling
Highly recommend watching the tutorial: Tutorial
-
Download the package or drag the folders to the project.
-
Add the Pool System Manager: The PoolSystemManager is the core engine that handles all pooling logic.
-
Create Pool Configurations: Each pool is defined by a PoolConfig.
You can create them through:
- Right-click in Project Window β Create β uPools β PoolConfig
π’ Get (Spawn)
GameObject bullet = PoolSystemManager.Instance.Get("Bullet");With position/rotation:
PoolSystemManager.Instance.Get(
"Bullet",
position: new Vector3(0, 1, 0),
rotation: Quaternion.identity
);Get a component directly:
var enemy = PoolSystemManager.Instance.Get<Enemy>("Enemy");π΄ Release (Despawn)
Release a single object:
PoolSystemManager.Instance.Release(gameObject);Release by key:
PoolSystemManager.Instance.Release("Bullet");
Release multiple:
```cs
PoolSystemManager.Instance.Release("Bullet", 5);Release all objects from a pool:
PoolSystemManager.Instance.ReleaseAll("Bullet");Release all pools:
PoolSystemManager.Instance.ReleaseAll();You can insert custom actions on Rent and Return by implementing IPoolCallbackReceiver. To run logic when the object is:
-
Created
-
Rented (spawned)
-
Returned (despawned)
-
Destroyed from pool (destroy array)
public class ExamplePoolable: MonoBehaviour, IPoolCallbackReceiver
{
public void OnInitialize() { }
public void OnRent() { }
public void OnReturn() { }
public void OnPoolDestroy() { }
}In the case of GameObjectPool or SharedGameObjectPool, this component will be retrieved from the object and its child objects, and the callbacks will be invoked accordingly. For other object pools like ObjectPool<T> or pools that inherit from ObjectPoolBase<T>, the callbacks are invoked for objects that implement IPoolCallbackReceiver.
If you create your own object pool by implementing IObjectPool<T, you will need to handle the IPoolCallbackReceiver calls yourself. Implement the necessary logic to invoke these callbacks as needed.
Log pool stats:
PoolSystemManager.Instance.LogPoolStatistics();Get active or inactive counts:
PoolSystemManager.Instance.GetActiveCount("Enemy");
PoolSystemManager.Instance.GetInactiveCount("Enemy");Get total objects ever created
int totalCreated = PoolSystemManager.Instance.GetTotalCreated("Bullet");Check if a pool exists
bool exists = PoolSystemManager.Instance.PoolExists("Bullet");Clear a pool:
PoolSystemManager.Instance.ClearPool("Enemy");Get all keys:
PoolSystemManager.Instance.GetAllPoolKeys();Every spawned object supports 4 reset strategies:
-
UsePrefabDefaults β resets to prefab transform
-
UseCustomDefaults β uses values defined in the PoolConfig
-
UseProvidedValues β uses values passed into Get()
-
KeepCurrent β leaves transform untouched
Set manually:
PoolSystemManager.Instance.SetPoolTransformMode("Bullet", TransformResetMode.KeepCurrent);Set Custom Defaults
PoolSystemManager.Instance.SetPoolTransformDefaults(
"Enemy",
new Vector3(0, 2, 0),
Quaternion.identity,
Vector3.one * 2f
);Get Reset Mode
TransformResetMode mode =
PoolSystemManager.Instance.GetPoolTransformMode("Enemy");Get parent transform of all pools
Transform root = PoolSystemManager.Instance.GetCurrentPoolParent();Get all category root transforms
var categories = PoolSystemManager.Instance.GetCategoryParents();Get all pool keys
IEnumerable<string> keys = PoolSystemManager.Instance.GetAllPoolKeys();Get as string[]
string[] keysArray = PoolSystemManager.Instance.GetAllPoolKeysArray();Get instantiation mode
InstantiationMode mode =
PoolSystemManager.Instance.GetPoolInstantiationMode("Bullet");uPools supports asynchronous object pooling using UniTask. When you add UniTask to your project, you can use AsyncObjectPool<T>, AsyncObjectPoolBase<T>, and IAsyncObjectPool<T> for asynchronous object pooling. These pools provide asynchronous versions of Rent, Prewarm, and CreateInstance while behaving like regular ObjectPool<T> in other aspects.
When using Addressables to generate GameObjects, you need to manage the resources of the loaded Prefabs. uPools offers AddressableGameObjectPool for this purpose, which can be used similarly to GameObjectPool.
// Address of the Prefab
var key = "Address";
var pool = new AddressableGameObjectPool(key);
// Usage is the same as GameObjectPool
var instance1 = pool.Rent();
var instance2 = pool.Rent(new Vector3(1f, 2f, 3f), Quaternion.identity);
pool.Return(instance1);
pool.Return(instance2);
pool.Dispose();A complete, optimized, and fully customizable Unity Object Pooling System with auto-categorizing, transform settings, overflow behavior, and callback support. This is the system I use across multiple projects β stable, flexible, and easy to extend.
Original Upools: https://github.com/AnnulusGames/uPools
You can also use the asynchronous version AsyncAddressableGameObjectPool by introducing UniTask.
π₯follow my YouTube @GameDevBox to find more Tutorials and Tips: GameDevBox
π₯See the tutorial for how you can set it up: https://youtu.be/kooOjK0K0bk
β’ X/Twitter β’ Instagram: β’ LinkedIn: β’ Discord Server: β’ itch.io: β’ Youtube Subscribe: