XPool icon indicating copy to clipboard operation
XPool copied to clipboard

Object pooling system for Unity.

XPool - Object Pooling System for Unity

Tests Build Release openupm

XPool_Frame

Created by Hiroya Aramaki (Makihiro)

What is XPool ?

XPool is an object pooling library for Unity.

This was developed to be able to do all the pooling expected in application development with just this library.

  • All your classes can be pooled.
  • Short code, easy to use.
  • Fast performance
  • Scalability
  • Tested. It works stably.

Table of Contents

  • 📥 Installation
  • 🔰 Usage
    • Unity Object Pool
      • ParticleSystem Pool
    • Pure C# Object Pool
    • Collection Pool
    • Non Allocated Collections
    • How to write custom pool ?
      • ParticleSystemPool implementation
    • Optimization
  • ✉ Help & Contribute
  • 📔 Author Info
  • 📜 License

📥 Installation

Download any version from releases.

Releases: https://github.com/mackysoft/XPool/releases

Install via PackageManager

Or, you can add this package by opening PackageManager and entering

https://github.com/mackysoft/XPool.git?path=Assets/MackySoft/MackySoft.XPool

from the Add package from git URL option.

Install via Open UPM

Or, you can install this package from the Open UPM registry.

More details here.

openupm add com.mackysoft.xpool

🔰 Usage

The full Scripting API is here.

Scripting API: https://mackysoft.github.io/XPool/api/MackySoft.XPool.html

Unity Object Pool (GameObject, Component)

Pooling of Unity Object (GameObject, Component) can be performed using GameObjectPool or ComponentPool<T>. These hierarchical objects can be rented by writing them in a similar way to Instantiate method.

// Example code is being written...

ParticleSystem Pool

Optimized pools are available for some of the components implemented in Unity.

This is an example of ParticleSystemPool usage.

public class HitParticleSystemEmitter : MonoBehaviour {

    [SerializeField]
    ParticleSystemPool m_HitParticleSystemPool = new ParticleSystemPool();

    void OnCollisionEnter (Collision collision) {
        // The rented ParticleSystem is automatically returned to the pool when completed.
        m_HitParticleSystemPool.Rent(collision.contacts[0],Quaternion.identity);
    }
}

If you need an optimized pool for other components, please refer to the How to write custom pool ? section, or give me feedback via issues or pull requests.

Object Pool (Pure C# Object)

FactoryPool<T> can be used to pool Pure C# Object.

Unity Object are not supported, as they behave differently from Pure C# Object in that they can be set to null externally with Destroy method.

// Give the capacity and factory method to the constructor.
var pool = new FactoryPool<MyClass>(8,() => new MyClass());

// Create new instance by factory if pool is empty.
MyClass instance = pool.Rent();

// Return instance to the pool.
pool.Return(instance);

Collection Pool (T[], List<T>, Qeueue<T>, Stack<T>, HashSet<T>, Dictionary<TKey,TValue>)

An optimized pool is provided for the generic collections provided in .NET Framework.

// Rent an array from the pool. 
// Note that the array length to be rented is the next two powers of minimumLength.
T[] array = ArrayPool<T>.Shared.Rent(minimumLength: 10);

// Return array to the pool.
ArrayPool<T>.Shared.Return(array);

// ListPool<T>, QueuePool<T>, StackPool<T>, HashSetPool<T>, DictionaryPool<TKey,TValue> are also available.
List<T> list = ListPool<T>.Shared.Rent();
Queue<T> queue = QueuePool<T>.Shared.Rent();
Stack<T> stack = StackPool<T>.Shared.Rent();
HashSet<T> hashSet = HashSetPool<T>.Shared.Rent();
Dictionary<TKey,TValue> dictionary = DictionaryPool<TKey,TValue>.Shared.Rent();

Non allocated collections

You can use the TemporaryCollections API that leverages ArrayPool<T>.

These collections are a struct and internally use array rented from ArrayPool<T>.

Therefore, it is fast and non-allocation.

// Create a temporary array.
var array = TemporaryArray<T>.Create(10);

// You must release collection when you are done using it.
array.Dispose();

// TemporaryList<T>, TemporaryQueue<T>, TemporaryStack<T> are also available.
TemporaryList<T> list = TemporaryList<T>.Create();
TemporaryQueue<T> queue = TemporaryQueue<T>.Create();
TemporaryStack<T> stack = TemporaryStack<T>.Create();

How to write custom pool ?

If you want to implement a more customized pool, you can quickly create one by using the provided base classes.

The base class of the pool is in the ObjectModel namespace.

  • MackySoft.XPool.ObjectMode.PoolBase<T>
  • MackySoft.XPool.Unity.ObjectModel.UnityObjectPoolBase<T>
  • MackySoft.XPool.Unity.ObjectModel.ComponentPoolBase<T>
using MackySoft.XPool.ObjectModel; // PoolBase<T> is here.

public class MyPool : PoolBase<MyClass> {

    public MyPool () {
    }

    public MyPool (MyClass original,int capacity) : base(original,capacity) {
    }

    // Called when Rent is invoked and there are no instances in the pool.
    protected override MyClass Factory () {
        return new MyClass();
    }

    // Called when an instance is rented from the pool.
    // This is also the case when a new instance is created by the Factory.
    protected override void OnRent (MyClass instance) {

    }

    // Called when an instance is returned to the pool.
    protected override void OnReturn (MyClass instance) {

    }

    // Called when the capacity is exceeded and the instance cannot be returned to the pool,
    // or when the instance is released by the ReleaseInstances method.
    protected override void OnRelease (MyClass instance) {
    
    }
}

ParticleSystemPool implementation

As an example, ParticleSystemPool is implemented using ComponentPoolBase<T>. Its functionality has been optimized for ParticleSystem.

using System;
using UnityEngine;
using MackySoft.XPool.Unity.ObjectModel; // ComponentPoolBase<T> is here.

[Serializable]
public class ParticleSystemPool : ComponentPoolBase<ParticleSystem> {

    [SerializeField]
    bool m_PlayOnRent;

    public bool PlayOnRent { get => m_PlayOnRent; set => m_PlayOnRent = value; }

    public ParticleSystemPool () {
    }

    public ParticleSystemPool (ParticleSystem original,int capacity) : base(original,capacity) {
    }

    protected override void OnCreate (ParticleSystem instance) {
        var main = instance.main;
        main.stopAction = ParticleSystemStopAction.Callback;
        var trigger = instance.gameObject.AddComponent<ParticleSystemStoppedTrigger>();
        trigger.Initialize(instance,this);
    }

    protected override void OnRent (ParticleSystem instance) {
        if (m_PlayOnRent) {
            instance.Play(true);
        }
    }

    protected override void OnReturn (ParticleSystem instance) {
        instance.Stop(true,ParticleSystemStopBehavior.StopEmitting);
    }

    protected override void OnRelease (ParticleSystem instance) {
        UnityEngine.Object.Destroy(instance.gameObject);
    }

    public class ParticleSystemStoppedTrigger : MonoBehaviour {

        ParticleSystem m_ParticleSystem;
        IPool<ParticleSystem> m_Pool;

        internal void Initialize (ParticleSystem ps,IPool<ParticleSystem> pool) {
            m_ParticleSystem = ps;
            m_Pool = pool;
        }

        void OnParticleSystemStopped () {
            m_Pool?.Return(m_ParticleSystem);
        }

    }
}

✉ Help & Contribute

I welcome feature requests and bug reports in issues and pull requests.

If you feel that my works are worthwhile, I would greatly appreciate it if you could sponsor me.

GitHub Sponsors: https://github.com/sponsors/mackysoft

📔 Author Info

Hiroya Aramaki is a indie game developer in Japan.

📜 License

This library is under the MIT License.