🐥

Unityでもっと簡単☆オブジェクトプール

2022/10/18に公開

Qiitaより転載
2020/4/29 初投稿


https://qiita.com/Akira_Kido_N/items/b5fa0c1ef324e57b0c28

3 年前の記事が未だにたまに LGTM とかされているので、一応今の自分だったらどう作るかなーと思って考えてみました。

以下になります。

public class ObjectPool : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    
    private readonly Queue<GameObject> _cache = new Queue<GameObject>();

    /// <summary>
    /// オブジェクトのインスタンスを取得します。
    /// キャッシュが無い場合、新しく生成します。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetOrCreate<T>() where T : Component
    {
        GameObject result;
        if (_cache.Count > 0)
        {
            result = _cache.Dequeue();
        }
        else
        {
            result = Instantiate(prefab);
            var ret = result.AddComponent<ObjectPoolReturn>();
            ret.ObjectPool = this;
        }
        result.SetActive(true);

        return result.GetComponent<T>();
    }

    public void ReturnToPool(GameObject go)
    {
        _cache.Enqueue(go);
    }
}

position とか設定してましたが、それは呼び出し元のオブジェクトで好きにしてね、という感じ。インスタンスを取得して GetComponent するだけ。場合によっては GetComponent しないメソッドも追加していい気もする。

ObjectPoolReturn はこんな感じ

public class ObjectPoolReturn : MonoBehaviour
{
    [CanBeNull] public ObjectPool ObjectPool { private get; set; }

    private void OnDisable()
    {
        if (ObjectPool != null)
        {
            ObjectPool.ReturnToPool(gameObject);
        }
    }
}

基本的に、プールで使うオブジェクトは Start ではなく OnEnable で初期化して、インスタンスを消す場合は gameObject.SetActive(false); しておけばオブジェクトプールを意識しなくていいって感じ。

とは言え、今オブジェクトプールを使うかと聞かれると微妙。ハードウェアのスペックが上がってるので Instantiate 自体がそんなに遅くないし、そこまで気にするなら ECS 使った方が絶対いい。

Discussion