流行りにのる
あいみょんの「Apple Watch使っている奴だいたい意識高い系」って歌詞が好きな皆さんこんにちは。「意外と便利だよ」とか言いながらアレコレと機能を紹介してくれるのですが、だいたい一週間ぐらいで飽きて普通の時計と化している姿をよく目にします。そりゃ、四六時中スマホをいじって画面を見ているのにわざわざメールの通知を腕時計に飛ばす必要ないですもんね。心拍数が測れて嬉しいのも最初の二、三日だけでしょうし、頻繁に充電が必要なデジタル時計という印象を持っている方も多いと思いますが私はPixel Watchが欲しいです。
オブジェトプール
Unity2021からオブジェトプール(Object Pool)が標準ライブラリに搭載されています。
オブジェトプールとは、例えばSTGの銃弾やモブの敵キャラなど、ゲーム内で繰り返し登場するオブジェクトを事前に保持しておいて必要なときにアクティブ/非アクティブを切り替えて利用する処理の事を指します。
事前にオブジェトを生成・保持しておく為、その分メモリを消費しますが、毎回オブジェクトを生成(Instantiate)And破棄(Destroy)する処理に比べてCPU負荷が掛からず、最適化(高速化)する手法の一つとして知られています。
今回はその標準ライブラリに搭載されているオブジェクトプールの簡易的な使い方と実際の動作について紹介します。
使い方
前述のようにオブジェトプールで必要な処理は
- オブジェトの生成と保持
- プールからの取り出し
- プールへの返却
となるので、ObjectPoolのコンストラクタではそれらの処理を行うための関数を指定する必要があります。
private ObjectPool<GameObject> m_objectPool; // オブジェクトプール private void Start() { // オブジェクトプールを作成します m_objectPool = new ObjectPool<GameObject> ( createFunc: funcCreate, actionOnGet: funcOnGet, actionOnRelease: funcOnRelase, actionOnDestroy: funcOnDestroy, collectionCheck: true, defaultCapacity: 10, maxSize: 10 ); }
各引数の意味は以下の通り
- createFunc:生成を行う関数
- actionOnGet:プールから貸し出す時の処理
- actionOnRelease:プールに返却する時の処理
- actionOnDestroy:プールの許容量を超えた時の削除処理
- collectionCheck:既にプールにあるオブジェトを追加した場合に例外とするか
- defaultCapacity:初期の許容量
- maxSize:最大許容量
他スクリプトからObjectPoolに対して貸出(Get)がコールされるとプール内にオブジェトが不足している場合はcreateFuncで指定した関数が呼ばれ、その関数でオブジェトの生成を実施、その後、プール内から取り出す際にactionOnGetで指定した関数が呼ばれます。
逆にObjectPoolに返却(Relase)する際にはactionOnReleaseで指定した関数が呼ばれます。
上の図の説明の通り、ObjectPoolはオブジェトの保持と容量管理しか行わないのでオブジェトの生成やアクティブ化/非アクティブ化はそれぞれの関数内で行う必要があります。
使用例
今回は鬼ごっこゲームを想定して以下ようなステージを用意
プレイヤーは画面中央の白い女の子で鬼(黒いstickman)から逃げる、という単純なゲームです。
鬼はObjectPoolで保持されており一定時間経つとObjectPoolから貸し出されて白円の部分に出現します。
プレイヤーは鬼に触れないように逃げるのですが、上のどくろマークのエリアに鬼が接触するとその鬼は消える(ObjectPoolへ返却する)ルールです。
鬼は一度の出現で8体必要ですが実際のゲームでの動作を見ると非アクティブ状態の鬼がアクティブ化され、不足分の鬼が生成されている事が分かると思います。
また逆に、どくろマークに触れた鬼は非アクティブ化されて画面から消えていきます。
以上、オブジェクトプールの簡単な使用例でした。