前書き
ここ最近はずっと遠距離武器を作っているためブログの記事も遠距離武器重視になっていますが、そんな第7回となる今回はPoolingの設定について紹介していこうと思います。
弾薬のPoolingに限りませんがPoolingをうまく使うことで動作を軽くすることも可能になります。例えば「同じオブジェクトを繰り返し使う」場合はぜひPoolingをうまく使ってみてください。TopDownEngineの場合は、そのようなPoolingが簡単に使えるようにデフォルトでスクリプトが作られていますので、今回はそのスクリプトの動きから紹介していこうと思います。
前回(第6回)の遠距離武器の作り方は以下になります。
Poolingについて
そもそもPoolingとは何か?について簡単に言うと
オブジェクトの生成と破棄によるパフォーマンスコストを減らすための機能になります。オブジェクトプールを使用することで、必要なときにオブジェクトを再利用できるようになり、頻繁に生成および破棄されるオブジェクト(弾丸や敵キャラクタ、エフェクトなどなど)に対して非常に有効な機能となっています。
簡単に言うと「オブジェクトを生成して破棄したあと、さらに再生成するようなオブジェクトに対してPoolingを使うとパフォーマンスが向上する」ような機能になります。
PoolingのUnityリファレンスマニュアルは以下になります。
弾薬にPoolingを設定した場合の動画は以下になります。攻撃するたびにKoalaGunBulletが有効になり、時間が経つと無効になります。さらに攻撃すると無効になっていたKoalaGunBulletが再度有効になることが分かります。
上記の方法の何がいいかというと、弾薬の生成方法としては
- Instantiateで新しく弾薬を生成してDestoryで破棄する方法
- Poolingを使用して弾薬を有効で生成し、無効で破棄する方法
の2つの方法が簡単に出来ますが、1つ目のInstantiateで生成しDestoryで破棄する方法はコストパフォーマンスが悪くゲームの動作に悪影響を与える方法になります。1つや2つ程度なら問題はないのですが繰り返し使う場合にInstantiateとDestoryはメモリの割り当てと解放を伴う高コストな操作となるため、頻繁にこれらを行うとゲームのパフォーマンスに悪影響を与えます。
2つ目のPoolingを使用して有効で生成し、無効にして破棄する方法は使用する前に一定数のオブジェクトを生成しておき、有効や無効にして使用する方法になります。この方法の利点としてInstantiateや生Destoryを使わないためメモリ割り当てなどのCPU負荷が高くないこと、事前にオブジェクトを作成しておくため、メモリの使用量がある程度一定で使用できることがあげられます。
ゲームを作るうえで最適化は避けては通れない道だと思いますので、頻繁に生成および破棄されるオブジェクト(弾丸や敵キャラクタ、エフェクトなど)はなるべくPoolingを使用したほうがいいかと思います。
TopDown EngineでのPoolingを使うためのスクリプト
TopDown EngineでPoolingを使用する場合は「MMSimpleObjectPooler」と「MMPoolableObject」の2つのスクリプトを使用しています。(今回はKoalaGunを基準としての紹介になるためとMMSimpleObjectPoolerとMMPoolableObjectとしています)
簡単にそれぞれのスクリプトについて説明していきます。
MMSimpleObjectPooler
MMSimpleObjectPoolerはオブジェクトプール管理クラスとなります。このクラスを使用することで、ゲームオブジェクトの生成と破棄を管理することができます。あくまでPoolingクラスを管理するためのスクリプトであるため、GameObjectToPoolにオブジェクトプールクラスを設定する必要があります。
MMPoolableObject
MMPoolableObjectはオブジェクトプールクラスとなります。このクラスはプールされたオブジェクトが再利用される際に必要な初期化やリセットなどの基本的な機能を保持しています。
TopDown EngineでのPoolingを使う方法は?
TopDown EngineでPoolingを使う方法はいろいろありますが、Demoにある使い方で紹介していこうと思います。
ProjectileWeaponでの使い方
ProjectileWeapon(遠距離武器)の場合は標準でObjectPoolerを使うようになっています。具体的に言うとProjectileWeaponのProjectiliesにObjectPoolerという項目があります。デフォルトではNoneになっていますが、ProjectileWeaponの内部処理で同じ階層にあるObjectPoolerクラスを探して見つかった場合はそのObjectPoolerクラスを弾丸として使うようになります。
実行してみると以下のようにNoneだったObjectPoolerが同じ階層にあるObjectPoolerクラスを設定するようになります。また、MMSimpleObjectPoolerのGameObjectToPoolにPoolableObjectクラスを設定すれば、TopDown EngineでPoolingを使うための下準備は完了です。
ProjectileWeaponの場合は攻撃を行うたびにPoolableObjectを有効にする処理が組まれているため、上記の設定を行うだけで最初に見せた動画のようにKoalaGunBulletが有効→無効→有効といった形で状態が変化するようになります。
Spawnerでの使い方
ProjectileWeapon以外でのPoolerクラスを使ったオブジェクトとしてMinimalSandbox2DにあるKoalaDungeonPortalがあります。↓以下のようなオブジェクトです。
このオブジェクトは右側にあるスイッチを有効にするとMMSimpleObjectPoolerのGameObjectToPoolで設定されているKoalaPoolableNinjaが出現します。
KoalaDungeonPortalを有効にすると以下のようにKoalaPoolableNinjaが生成されるようになります。KoalaPoolableNinjaもPoolableObjectとなるため、倒してもSpawnerで設定された時間ごとに再生成される作りになっています。
自分が調べた限りPoolingを使ってるのは上記2つの事例かなと思います。他にもMMFeedbacksでObjectを生成するときもPoolingを使うことができるのですがその方法はまた後程紹介していこうと思います。
まとめ
今回はPoolingの設定について紹介しました。
遠距離武器にPoolingの設定をした弾薬を使用したい場合、
- MMPoolableObjectを使ってPoolableObjectクラス(弾薬)を作成する
- MMSimpleObjectPoolerなどのObjectPoolerクラス(管理クラス)を使って1.で作成したPoolableObjectクラス(弾薬)を設定する。
- ProjectileWeaponなどでObjectPoolerクラス(管理クラス)を使用する。
と、言った手順を踏む必要があります。KoalaGunなどの作りを見るとだいたいの処理の流れが見えてくると思うので詳細を知りたい場合は実装を見てみるのがいいかと思います。
遠距離武器作成の一環としてPoolingの説明をさせていただきましたが、遠距離武器を作る以外でも頻繁に生成および破棄されるオブジェクト(弾丸や敵キャラクタ、エフェクトなどなど)を使用する場合には有効な機能です。設定方法もそこまで難しくはないので、最適化する余裕がありましたらまずはPoolingを使ってみてはいかがでしょうか?
コメント