LoginSignup
0
1

More than 5 years have passed since last update.

Unityでオブジェクトプール実装+拡張

Posted at

Unityのオブジェクトプールの実装と拡張についてメモを残しときます。
現在開発中のゲーム「ProjectActress(仮)」にて実装済みです。

オブジェクトプールってなんぞ

参考資料:
http://marudice.hatenablog.jp/entry/2016/11/25/013344

ゲーム開発とかで組んだりするタスクシステムをもうちょっと限定的にしたイメージかな?
(タスクシステムも方言がありすぎるわけだけど)

この機能によって、使用オブジェクトについて動作速度を気にすることなく、動的に追加、および動的に削除(に見える)できるようになります。

オブジェクトプールの拡張

ただ上記の実装だと問題がありまして、
「1種類のキャラしかオブジェクトプール実装できない」
ということになります。
よって、オブジェクトプールを並列管理できるクラスを作成します。
(一部しか書かないけどご了承ください)
static宣言が多いけどご了承ください。
あと16って数値についてはあまり意味ありません。
急ぎ実装したので数値を直に入力してます。

オブジェクトプール(並列版)

EnemyPool.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class EnemyPool<T> : MonoBehaviour {
    private static GameObject[] mOriginal = new GameObject[16];
    private static Stack<T>[] mObjPool = new Stack<T>[16];
    private static Stack<T> objPool_seed;
    private static bool[] isInstanced = new bool[16];

    public static void SetOriginal(GameObject origin, int number ) {
        //オブジェクトプールの数は制限しておく。
        if( number >= 16){
            return ;
        }

        //オブジェクトプールのスタックを動的生成
            objPool_seed = new Stack<T>();
            mObjPool[number] = objPool_seed;

        //オブジェクトをセット。
        mOriginal[number] = origin;
    }
    public static T Create(int number)
    {
        T obj;

        if (mObjPool[number].Count > 0)
        {
            obj = Pop(number);
        }
        else
        {
            var go = Instantiate<GameObject>(mOriginal[number]);
            obj = go.GetComponent<T>();
        }
        (obj as EnemyPool<T>).Init();
        return obj;
    }

    /*
        Stackからポップする(取り出す)
        LIFOの形になる。
     */
    private static T Pop(int number)
    {
        var ret = mObjPool[number].Pop();
        return ret;
    }

    /*
        データをプールする。

        Staticでデータを残して再度呼び出しの形で利用する。
        (HP等の初期化はゲームごとに行う事)
     */
    public static void Pool(T obj, int number)
    {
        (obj as EnemyPool<T>).Sleep();
        mObjPool[number].Push(obj);
    }

    /*
        キューをクリアする。

        Staticなデータなので、次のシーン呼び出しor再度のシーン呼び出しにて
        残っているデータを参照しようとしてエラーを吐くらしいので、
        シーン初期化の際は必ず呼び出すこと。
     */
    public static void Clear(int number)
    {
        mObjPool[number].Clear();
    }

    public abstract void Init();
    public abstract void Sleep();
}

プーリングするGameObjectはInspector上で指定可能なので、ステージごとに使用するGameObjectを指定して使ってます。

オブジェクトプール使うときの注意点

ロックオンシステムみたいに「対象オブジェクトを継続して目標に捉える」ケースがある場合、オブジェクトを再利用すると、新しく出てきたオブジェクトが目標として捉えられるケースが存在します。
これはオブジェクト使い回しの弊害ってヤツですね。
なのでその場合はロックオン解除を別途実装する形にしてください。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1