/XPool

Object pooling system for Unity.

Primary LanguageC#MIT LicenseMIT

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.

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

The full Scripting API is here.

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

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...

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.

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);

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();

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();

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) {
    
    }
}

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);
        }

    }
}

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

Hiroya Aramaki is a indie game developer in Japan.

This library is under the MIT License.