はかせのラボ

私の頭の中を書いていく雑記ブログです

プログラミング オブジェクトプールについて 実装編

あいさつ

どうも、はかせです。
今回は前回書いたオブジェクトプールの実装編です。

実装

実装概要

今回は久しぶりにUnityC#を使って実装してみます。
(久しぶりにUnity触りたくなったんです)

今回は複雑な機能は持たせずにオブジェクトを保持し
格納と取り出しと不足時に適当なものを作る
というものを作ります。

オブジェクトプール本体の実装

public class ObjectPool : MonoBehaviour
{
    private Queue<GameObject> mObjectPool;
    [SerializeField,Tooltip("プール不足時に追加生成するもの")]
    private GameObject mAddInstantiateObject;
    
    private void Awake()
    {
        mObjectPool = new Queue<GameObject>();
    }

    /// <summary>
    /// 渡されたGameObjectをプールに格納する
    /// </summary>
    /// <param name="inObj"></param>
    public void SetGameObjcet(GameObject inObj)
    {
        //格納時に非アクティブ化する
        inObj.SetActive(false);
        //プールに格納
        mObjectPool.Enqueue(inObj);
    }

    /// <summary>
    /// プールからオブジェクトを取り出す
    /// プールが空であれば新規作成して返す
    /// </summary>
    /// <returns></returns>
    public GameObject GetGameObject()
    {
        GameObject gameObject;
        //プールしたものが無ければ新規生成
        if (mObjectPool.Count <= 0) gameObject = Instantiate(mAddInstantiateObject);
        //あれば取り出す
        else gameObject = mObjectPool.Dequeue();
        //渡す前にアクティブ化する
        gameObject.SetActive(true);
        return gameObject;
    }
}

めちゃめちゃ雑な実装ですがこれでオブジェクトプールはできます。

格納時と取り出し時にGameObjectのアクティブを操作しています。
こうすることで初期化処理をOnEnableに
終了処理にOnDisableにそれぞれ記述できます。

自作クラスを作ってやってそのクラスのメソッド呼び出しでもいいですが、
せっかくエンジン使ってるんですから
乗っかれる部分は乗っかったほうがいいと思っています。

プールされるオブジェクト

public class PoolObject : MonoBehaviour
{
    private ObjectPool mPool;
    private Rigidbody mRb;

    /// <summary>
    /// 必要な変数の取得
    /// </summary>
    private void Awake()
    {
        mPool = GameObject.Find("GameObjectPool").GetComponent<ObjectPool>();
        mRb = gameObject.GetComponent<Rigidbody>();
    }

    /// <summary>
    /// 初期化処理
    /// </summary>
    private void OnEnable()
    {
        transform.position = Vector3.zero;
    }

    /// <summary>
    /// 終了処理
    /// </summary>
    private void OnDisable()
    {
        mRb.velocity = Vector3.zero;
    }

    /// <summary>
    /// 自身をプールへ格納する
    /// </summary>
    /// <param name="other"></param>
    private void OnTriggerEnter(Collider other)
    {
        mPool.SetGameObjcet(this.gameObject);
    }
}

プールされる側につけるスクリプトです。
プールへ自身を格納する処理と
初期化、終了処理があります。

多分ガチガチに設計してやるんだったら
このクラスとObjectPoolでプール関連の処理は完結してると楽だと思います。
今回はただオブジェクトプールの動きができればいいので
そんな凝った作りにしてません。

実行

それでは実行してみます。
キー入力を受けてオブジェクトの生成を行います。
このときオブジェクトプールを使っているためプールに何かあれば
使いまわします。
格納は床として置いているPlaneに当たった時にされています。

ヒエラルキー上のオブジェクトのアクティブ状態が切り替わって
使いまわされているのがわかると思います。
youtu.be

あとがき

今回はオブジェクトプールの実装編でした。
そんなに凝った作りにしてないのでやってることは
分かりやすいと思います。

それにしても久しぶりにUnityC#触りましたが
やっぱ楽ですね。
それぞれ50行も書かずに目的の機能ができてしまいました。
(最近の言語ならむしろこれくらいが当たり前か)

勉強目的とかつよつよエンジニアアピールをしたいときは向かないですけど、
それ以外ならやっぱエンジン使って開発するのが
楽かつ早くそれでいてクオリティアップがしやすいので良いですね。

それでは今回はこの辺でノシ