uPools Object Pooling for Unity

repository·main·Indexed 42 days ago

https://github.com/annulusgames/upools

A lightweight and flexible object pooling system for Unity version 1.0.1. It provides specialized pools for GameObjects, regular C# classes, and Addressables, including support for UniTask-based asynchronous operations via AsyncObjectPool<T> and AsyncAddressableGameObjectPool. Features include SharedGameObjectPool for easy Instantiate/Destroy replacement, custom pool creation via ObjectPoolBase<T>, and lifecycle callbacks through the IPoolCallbackReceiver interface.

Tokens
3.1K
Snippets
10
Records
12
Agent score
3%

What's inside uPools

  1. Use asynchronous pooling with UniTask

    main

    If your project includes UniTask, uPools provides asynchronous pooling capabilities via AsyncObjectPool<T>, AsyncObjectPoolBase<T>, and IAsyncObjectPool<T>.

    In these pools, Rent(), Prewarm(), and CreateInstance() are asynchronous operations, while other methods remain identical to the standard synchronous pools.

  2. Asynchronous pooling with UniTask

    main

    If your project includes UniTask, uPools provides asynchronous pooling capabilities. You can use the following types to perform asynchronous operations like Rent, Prewarm, and CreateInstance:

    • AsyncObjectPool<T>
    • AsyncObjectPoolBase<T>
    • IAsyncObjectPool<T>

    These behave similarly to the standard ObjectPool<T> but support async/await patterns.

  3. Quick Start with SharedGameObjectPool

    main

    The simplest way to implement pooling is to use SharedGameObjectPool. This allows you to replace standard Unity Instantiate() and Destroy() calls with Rent() and Return().

    • Use SharedGameObjectPool.Prewarm(prefab, count) to prepare a specific number of objects in advance.
    • Use SharedGameObjectPool.Rent(prefab) to retrieve an instance.
    • Use SharedGameObjectPool.Return(instance) to return an instance to the pool.
    using UnityEngine;
    using uPools;
    
    public class Example : MonoBehaviour
    {
        [SerializeField] GameObject prefab;
    
        void Start()
        {
            // Pre-warm objects in advance
            SharedGameObjectPool.Prewarm(prefab, 10);
    
            // Retrieve objects from the pool
            var instance = SharedGameObjectPool.Rent(prefab);
    
            // Return the object to the pool after use
            SharedGameObjectPool.Return(instance);
        }
    }
  4. Install uPools via Unity Package Manager or manifest.json

    main

    To install uPools in your Unity project, you can use the Package Manager or manually edit your Packages/manifest.json file.

    Requirements:

    • Unity 2019.4 or higher

    Option 1: Package Manager

    1. Open Window > Package Manager.
    2. Click the "+" button and select Add package from git URL.
    3. Enter the following URL:

    https://github.com/AnnulusGames/uPools.git?path=/Assets/uPools

    Option 2: manifest.json Add the following dependency to your Packages/manifest.json file:

    {
        "dependencies": {
            "com.annulusgames.u-pools" : "https://github.com/AnnulusGames/uPools.git?path=/Assets/uPools"
        }
    }
    https://github.com/AnnulusGames/uPools.git?path=/Assets/uPools
  5. Install uPools via Unity Package Manager

    main

    To install uPools, use the Unity Package Manager to add the package via its Git URL.

    1. Open Window > Package Manager.
    2. Click the + button and select Add package from git URL....
    3. Enter the following URL: https://github.com/AnnulusGames/uPools.git?path=/Assets/uPools

    Alternatively, you can manually add the dependency to your Packages/manifest.json file.

    {
        "dependencies": {
            "com.annulusgames.u-pools" : "https://github.com/AnnulusGames/uPools.git?path=/Assets/uPools"
        }
    }
  6. Pool GameObjects with GameObjectPool

    main

    The GameObjectPool class is specialized for Unity GameObjects. When an object is rented, it is automatically activated; when returned, it is deactivated.

    Key Methods:

    • Rent(): Retrieves an object.
    • Rent(position, rotation, parent): Retrieves an object with specific transform parameters.
    • Return(instance): Returns the object to the pool.
    • Dispose(): Destroys the pool and all associated GameObjects.
    // GameObject prefab
    GameObject original;
    
    var pool = new GameObjectPool(original);
    
    // Use Rent() to retrieve an object
    var instance1 = pool.Rent();
    
    // You can specify position, rotation, and parent Transform when retrieving
    Transform parent;
    var instance2 = pool.Rent(new Vector3(1f, 2f, 3f), Quaternion.identity, parent);
    
    // Use Return() to return the object
    pool.Return(instance1);
    pool.Return(instance2);
    
    // Dispose() to destroy the pool and all GameObjects
    pool.Dispose();
  7. Pool regular C# classes with ObjectPool<T>

    main

    To pool standard C# classes (non-Unity objects), use ObjectPool<T>. You must provide a creation function and can optionally provide callbacks for renting, returning, and destruction.

    Warning: Object pools are not thread-safe.

    Key Methods:

    • Rent(): Retrieves an instance.
    • Return(instance): Returns an instance to the pool.
    • Prewarm(count): Pre-instantiates objects.
    • Count: Gets the number of objects in the pool.
    • Clear(): Removes all objects from the pool.
    • Dispose(): Destroys the pool.
    class PooledObject { }
    
    var pool = new ObjectPool<PooledObject>(
        createFunc: () => new PooledObject(), // How to create the object
        onRent: instance => { },              // Optional: logic when rented
        onReturn: instance => { },            // Optional: logic when returned
        onDestroy: instance => { }             // Optional: logic when pool is destroyed
    );
    
    pool.Prewarm(10);
    var instance = pool.Rent();
    pool.Return(instance);
    
    var count = pool.Count;
    pool.Clear();
    pool.Dispose();
  8. Use IPoolCallbackReceiver for custom Rent/Return logic

    main

    You can implement the IPoolCallbackReceiver interface on your classes to trigger custom logic automatically during the pooling lifecycle.

    • For GameObjectPool or SharedGameObjectPool: The system searches for this component on the GameObject or its children. When the object is rented or returned, OnRent() and OnReturn() are invoked.
    • For ObjectPool<T> or ObjectPoolBase<T>: The callbacks are invoked if the pooled object itself implements IPoolCallbackReceiver.

    Note: If you implement your own IObjectPool<T>, you are responsible for manually invoking these callback methods.

    public class CallbackExample : MonoBehaviour, IPoolCallbackReceiver
    {
        public void OnRent()
        {
            Debug.Log("Rented");
        }
    
        public void OnReturn()
        {
            Debug.Log("Returned");
        }
    }
  9. Pool Addressables with AddressableGameObjectPool

    main

    When using Unity Addressables, you can use AddressableGameObjectPool to manage the lifecycle of loaded Prefabs. It functions similarly to GameObjectPool but uses an Addressable key instead of a direct GameObject reference.

    Key Features:

    • Use AddressableGameObjectPool(key) to initialize.
    • Supports standard Rent() and Return() methods.
    • If UniTask is present, you can use AsyncAddressableGameObjectPool for asynchronous operations.
    // 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();
  10. Use IPoolCallbackReceiver for Rent/Return callbacks

    main

    Implement the IPoolCallbackReceiver interface on a component to trigger logic automatically when an object is rented or returned.

    Behavior by Pool Type:

    • GameObjectPool or SharedGameObjectPool: The pool searches the object and its children for components implementing IPoolCallbackReceiver and calls OnRent() or OnReturn() on them.
    • ObjectPool<T> or ObjectPoolBase<T>: If the pooled object T implements IPoolCallbackReceiver, the callbacks are triggered.
    • Custom IObjectPool<T>: You are responsible for manually calling these callbacks in your implementation.
    public class CallbackExample : MonoBehaviour, IPoolCallbackReceiver
    {
        public void OnRent()
        {
            Debug.Log("rented");
        }
    
        public void OnReturn()
        {
            Debug.Log("returned");
        }
    }
  11. Create custom object pools by inheriting from ObjectPoolBase<T>

    main

    To implement a custom pooling logic, inherit from ObjectPoolBase<T> and override the following protected methods:

    • CreateInstance(): Returns a new instance of T.
    • OnRent(instance): Logic to execute when an object is rented.
    • OnReturn(instance): Logic to execute when an object is returned.
    • OnDestroy(instance): Logic to execute when an object is destroyed (e.g., during Clear or Dispose).

    Alternatively, you can implement the IObjectPool<T> interface for full control.

    class PooledObject { }
    
    public sealed class CustomObjectPool : ObjectPoolBase<PooledObject>
    {
        protected override PooledObject CreateInstance()
        {
            return new PooledObject();
        }
    
        protected override void OnDestroy(PooledObject instance)
        {
            // Add actions when the object is destroyed in Clear or Dispose
        }
    
        protected override void OnRent(PooledObject instance)
        {
            // Add actions when rented
        }
    
        protected override void OnReturn(PooledObject instance)
        {
            // Add actions when returned
        }
    }
  12. Create a custom object pool by inheriting ObjectPoolBase<T>

    main

    To implement a custom pooling logic, inherit from ObjectPoolBase<T>. You must override CreateInstance() and can optionally override OnRent, OnReturn, and OnDestroy to handle lifecycle events.

    class PooledObject { }
    
    public sealed class CustomObjectPool : ObjectPoolBase<PooledObject>
    {
        protected override PooledObject CreateInstance()
        {
            return new PooledObject();
        }
    
        protected override void OnDestroy(PooledObject instance)
        {
            // Logic for when objects are destroyed via Clear or Dispose
        }
    
        protected override void OnRent(PooledObject instance)
        {
            // Logic for when an object is rented
        }
    
        protected override void OnReturn(PooledObject instance)
        {
            // Logic for when an object is returned
        }
    }