オブジェクトプール
これまでココのコイン落としではコイン投入及びコイン回収処理をInstantiate()とDestroy()で行っていました。
ですがこのやり方だとコインを連打したり、景品コインが大量に落下した時、コインを一度に回収した時にカクつくなど、明らかに処理が追いついていない事がありました。
そこで色々と調べた所、どうやら「オブジェクトプール」という、オブジェクトを毎回削除せずにプールに貯めて次回のInstantiate()の代わりに使いまわす事で、無駄なメモリ処理を削減するデザインパターンがあるようです。
PoolManagerアセット
Unityアセットでオブジェクトプールを簡単に実現できる「PoolManager」というものがあるらしいので、それを使ってみる事にしました。評価もとても高く、25$程度と手頃な値段でデザインパターンの堅実な実装が容易に出来るというのは素晴らしいです。
実装方法
パッケージをインポートした後、以下のように実装します。
SpawnPoolを用意する
シーン上にSpawnPoolコンポーネントをアタッチしたオブジェクトを配置します。このコンポーネントのInspectorでオブジェクトプール機能の設定を行います。またデフォルトではこのオブジェクトが生成&プールされた子オブジェクトの親オブジェクトとなります。
SpawnPoolの設定
Pool Name:一意なプール名を付けます。スクリプト側で参照されますので分かりやすい名前にします。
Match Pool Scale : 生成される子オブジェクトが、親オブジェクト(SpawnPoolをアタッチしたオブジェクト)に合わせてスケールされます。子オブジェクトがUIの時に使うようです。
Match Pool Layer : 生成される子オブジェクトのレイヤを親オブジェクトと同一のレイヤにします。
Don’t Reparent : 生成されるオブジェクトをSpawnPoolがアタッチされたオブジェクトの子にしません。
Don’t Destroy On Load : 生成されるオブジェクトのDontDestroyOnLoadを有効にします。シーンをまたいでプールを維持したい時にチェックします。
Log Messages : PoolManagerの処理内容がログに表示されます。
Per-Prefab Pool Options : 生成&プールされるオブジェクトのプレハブをここに事前に指定します。
今回はコインはUI要素でもないですし、レイヤも関係ないですし、親も変える必要がなく、シーンをまたぐ必要もないのでPool Nameだけを指定しました。
プレハブを登録する
Per-Prefab Pool Optionsにプレハブを登録していきます。右の+を押すと登録欄が一つ出てきます。
prefab :プールする予定のプレハブです。右の○からはシーン上のオブジェクトしか指定できないようなので、Project欄からプレハブをD&Dします。
preload Amout : あらかじめ生成してプールしておくオブジェクトの数を指定します。今回は20個にしておきます。
preload Time : チェックするとPreload FramesとPreload Delayが設定できます。プリロードの生成にかけるフレーム数と、プリロードの遅延時間を指定できます。
limit Instances : プールされるオブジェクトの数を制限します。これを超えてSpawnされてもNullが返ります。Limit Amountで上限を指定し、limit FIFOをチェックすると、上限を超えた場合に古いオブジェクトから使いまわします。
cull Despawned : 使われていないインスタンスを削除します。基本的に使わない方が良いらしいです。オブジェクト数がcull Aboveを超えたら、cull Delay秒ごとにcull Max Per Pas個ずつオブジェクトを削除します。
log Messages : ログメッセージを出力します。
コイン落としは仕様上画面内に100枚程度しか蓄積されませんのでPreload Amount以外は未チェックです。ただ、長時間プレイしているとコインが想定外な動きをしてコライダーを飛び抜けて無限に落下してしまうものが出て来る可能性も0ではないので、limit InstancesをチェックしてLimit Amountを150くらいにしてlimit FIFOをチェックしてもよいかもしれません。
今回は、コイン、アイテムカプセル、石のプレハブをまとめて一つのプールに登録しました。
既存スクリプトの編集
これまでコインなどをInstantiate()やDestroy()していた部分を編集します。
//コイン生成 //GameObject coin = (GameObject)Instantiate( // coinPrefab, // initPos, // Quaternion.Euler(90.0f, 0.0f, 0.0f) //); var obj = PoolManager.Pools["CoinPool"].Spawn(coinPrefab); obj.position = initPos; obj.rotation = Quaternion.Euler(90.0f, 0.0f, 0.0f); GameObject coin = obj.gameObject; //以下coinに速度やトルクなど与える //コイン削除 private void OnTriggerEnter(Collider other) { //Destroy(other.gameObject); PoolManager.Pools["CoinPool"].Despawn(other.transform); }
これだけで完成です。本当に簡単にオブジェクトプールを実装することができました!
コメント