🚀
Unityで簡単☆オブジェクトプール
Qiitaより転載
2017/1/16 初投稿
2017/2/5 追記:デキューするときにデキューしたオブジェクトを返すようにしました。
Unityでプレハブ使うとき、Instantiate使いたくねーなー、でもプール作るのめんどくさいなー、って思っとことありますよね? あるんですよ。そんなあなたに、簡単オブジェクトプールをご紹介。
プールするオブジェクト
まずプールするためのルートオブジェクトを作ります。プールするオブジェクトはこれを継承することで作ります。
PoolableObject.cs
using UnityEngine;
// abstractである必要はないけど、僕はこれを単体で使うことがないので
public abstract class PoolableObject : MonoBehaviour
{
// 使い終わったら戻すためにプールへの参照を持ちます。
public GenericPool Pool { private get; set; }
// Start()が呼べないのでInitを別途実装します。
public abstract void Init();
/// <summary>
/// まあ、忘れそうなので。
/// プールに戻します。(実態はReturnToPool())
/// </summary>
/// <param name="obj"></param>
protected new void Destroy(Object obj)
{
ReturnToPool();
}
/// <summary>
/// プールに戻します。
/// </summary>
protected void ReturnToPool()
{
Pool.Return(this);
}
}
プール本体
で、上を実際に作るプールはこちら。
GenericPool.cs
using System.Collections.Generic;
using UnityEngine;
// 名前がGenericなのはジェネリクスを使おうとして失敗した名残。。
public class GenericPool : MonoBehaviour
{
// ここにプールしたいPrefabをエディタで指定します
[SerializeField]
private PoolableObject PooledObject;
// プールのサイズを指定しておきます(メモリ節約)
// 必要に応じて調整してください。
private const int PoolSize = 50;
// プールの実態。Queueを使用します。
private readonly Queue<PoolableObject> _pool =
new Queue<PoolableObject>(PoolSize);
// どうでもいい定数。あんまり回転いじらないのでゼロを作ってるだけ。
private static readonly Quaternion NoRotation = Quaternion.Euler(0, 0, 0);
/// <summary>
/// プールにオブジェクトがあればそれを利用します。
/// 無ければ新たにオブジェクトをInstantiateします。
/// </summary>
/// <param name="position"></param>
public T Place<T>(Vector2 position) where T : PoolableObject
{
return (T) Place(position);
}
/// <summary>
/// プールにオブジェクトがあればそれを利用します。
/// 無ければ新たにオブジェクトをInstantiateします。
/// </summary>
/// <param name="position"></param>
public PoolableObject Place(Vector2 position)
{
PoolableObject obj;
if (_pool.Count > 0)
{
obj = _pool.Dequeue();
obj.gameObject.SetActive(true);
obj.transform.position = position;
obj.Init();
}
else
{
obj = Instantiate(PooledObject, position, PooledObject.transform.rotation);
obj.Pool = this;
obj.Init();
}
return obj;
}
/// <summary>
/// オブジェクトをプールに戻します
/// </summary>
/// <param name="obj"></param>
public void Return(PoolableObject obj)
{
obj.gameObject.SetActive(false);
_pool.Enqueue(obj);
}
}
使い方
使い方はいたってシンプル。
- プールしたいプレハブをPoolableObject継承にする。
- エディタ上で空のGameObjectを作って、それにGenericPoolをAdd Componentする。
- GenericPoolのPooledObjectに1.で作ったプレハブをセットする。
- GenericPoolのPlace()を呼ぶ。
以上です。
PoolableObjectを継承した例はこんな感じ。シューティングで使う弾。
Bullet.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D), typeof(Collider2D))]
public class Bullet : PoolableObject
{
[SerializeField]
private Rigidbody2D Rigidbody;
[SerializeField]
protected Vector2 Velocity;
public override void Init()
{
// 移動速度を設定する
Rigidbody.velocity = Velocity;
}
void Update ()
{
// 上に向かって進むので、y > 5になったらプールに戻す。
if (transform.position.y > 5f)
{
ReturnToPool();
}
}
void OnTriggerEnter2D(Collider2D col)
{
// 何かにぶつかったらプールに戻す
ReturnToPool();
}
}
Discussion