Game Kit におけるオブジェクトプーリング

確認済のバージョン: 2017.3

-

難易度: 初級

Game Kit は一部のシステムに、拡張可能なオブジェクトプーリングシステムを使用しています。以下の説明は、Game Kit を使用する上で必ず必要となる知識ではありませんが、目的に応じて拡張したい場合に役立つ内容となっています。

オブジェクトプーリングシステムを拡張するには、2 つのクラスを作成する必要があります。1 つは ObjectPool から継承し、もう 1 つは PoolObject から継承します。ObjectPool から継承するクラスはプール自体であり、PoolObject から継承するクラスはプール内の各プレハブのラッパーです。この 2 つのクラスはジェネリック型によって結び付けられています。ObjectPool および PoolObject は必ず同じ 2 つのジェネリック型を(ObjectPool から継承するクラス、PoolObject から継承するクラスの順で)持っている必要があります。以下はその分かりやすい例です。

Code snippet

public class SpaceshipPool: ObjectPool<SpaceshipPool, Spaceship> {
    …
}

public class Spaceship: PoolObject<SpaceshipPool, Spaceship> {
    …
}

このような形になるのは、プールがそれに含まれるオブジェクトの型を把握し、オブジェクトがその所属するプールの型を把握している状態にするためです。これらのクラスは 3 つ目のジェネリック型を持つ場合もあります。これは、PoolObject の WakeUp 関数のパラメーターを含めたい場合にのみ必要となります。この WakeUp 関数は、PoolObject がプールから取得された時に呼び出されます。例えばスペースシップのアクティベート時に燃料の残量を検知しなければならない場合は、以下のように float 型を 1 つ追加することもできます。

Code snippet

public class SpaceshipPool: ObjectPool<SpaceshipPool, Spaceship, float> {
    …
}

public class Spaceship: PoolObject<SpaceshipPool, Spaceship, float> {
    …
}

デフォルトでは PoolObject には以下のフィールド含まれます。

  • inPool ― この bool 型は、PoolObject が現在プール内にあるかアクティブであるかを表します。

  • instance ― このゲームオブジェクトは、この PoolObject がラップする、インスタンス化されたプレハブです。

  • objectPool ― この PoolObject が属するオブジェクトプールです。このクラスの ObjectPool のタイプと同じタイプを持っています。

PoolObject には以下の仮想関数も含まれます。

  • SetReferences ― PoolObject の初回作成時に呼び出されます。この関数の目的は、参照をキャッシュすることにより、PoolObject がアクティベートされる度にそれらを集める必要性をなくすことですが、それ以外の一時的な使用は可能になります。

  • WakeUp ― PoolObject がアクティベートされてプールから集められる度に呼び出されます。この関数の目的は PoolObject が使用される度に必要なすべての設定を行うことです。クラスに第 3 のジェネリックパラメーターが与えられた場合は、そのタイプのパラメーターで WakeUp が呼び出せるようになります。

  • Sleep ― PoolObject がプールに戻される度に呼び出されます。この関数の目的は、PoolObject が使用された後に必要なすべてのクリーニング実行することです。

  • ReturnToPool ― デフォルトでは単純に PoolObject をプールに戻しますが、追加的な機能が必要な場合はオーバーライド可能です。

ObjectPool は MonoBehaviour であり、したがってゲームオブジェクトに追加可能です。デフォルトでは以下のフィールドが含まれます。

  • Prefab ― プール作成のために複数回インスタンス化されるプレハブへの参照です。

  • InitialPoolCount ― Start メソッド内で作成される PoolObject の数です。

  • Pool ― PoolObject のリストです。

ObjectPool には以下の関数も含まれます。

  • Start ― 初回のプール作成が行われる場所です。ObjectPool 内に Start 関数があると、基底クラスの Start 関数が隠蔽されます。

  • CreateNewPoolObject ― PoolObject が作成されてその SetReferences を呼び出し、その後 Sleep 関数を呼び出す時に呼び出されます。仮想関数ではないのでオーバーライドは不可ですが、protected なので必要に応じて継承するクラス内で呼び出すことができます。

  • Pop ― プールから PoolObject を取得するために呼び出されます。デフォルトでは、inPool フラグが true に設定された PoolObject を検索して最初に検知されたものを戻します。true に設定されたものがなければ、新しく作成してそれを戻します。戻す PoolObject に WakeUp を呼び出します。これは仮想関数であり、オーバーライド可能です。

  • Push ― PoolObject をプール内に戻すために呼び出されます。デフォルトでは単純に inPool フラグを設定して PoolObject に Sleep を呼び出しますが、仮想関数なのでオーバーライド可能です。

オブジェクトプールシステムの使用例の全体は、BulletPool に関するドキュメンテーションおよびスクリプトをご覧ください。

BulletPool

BulletPool MonoBehaviour は BulletObject のプールであり、各 BulletObject が弾丸のプレハブをラップします。BulletPool は Ellen と敵の両方に使用されていますが、使われ方が若干異なっています。Ellen のほうは、親ゲームオブジェクトに BulletPool MonoBehaviour がアタッチされ、Prefab フィールドに Bullet プレハブが設定されています。一方敵のほうは BulletPool が EnemyBehaviour クラス内にあります。GetObjectPool 静的関数を使って、BulletPools を、頻繁に作成することなく使用できるようにしています。

BulletPool クラスには以下のフィールドが含まれます。

  • Prefab ― 使用したい弾丸プレハブを設定します。

  • Initial Pool Count ― 最初にプール内に作成される弾丸の数です。一度に使用する最大数をここに設定してください。より多く必要になった場合はランタイムで作成されます。

  • Pool ― プール内の BulletObject です。これはインスペクターでは表示されません。

BulletPool クラスには以下の関数が含まれます。

  • Pop ― プールから BulletObject 1 つを取得するために使用します。

  • Push ― BulletObject をプールに戻すために使用します。

  • GetObjectPool ― 特定のプレハブに対して適切な BulletPool を探す静的関数です。

弾丸は、1 つの BulletObject としてプールから取得されます。BulletObject クラスには以下のフィールドが含まれます。

  • InPool ― その特定の弾丸がプール内にあるか、または使用中であるかを表します。

  • Instance ― インスタンス化されたプレハブです。

  • ObjectPool ― その BulletObject が属する BulletPool への参照です。

  • Transform ― そのインスタンスの Transform コンポーネントです。

  • Rigidbody2D ― そのインスタンスの Rigidbody2D コンポーネントです。

  • SpriteRenderer ― そのインスタンスの SpriteRenderer コンポーネントへの参照です。

  • Bullet ― そのインスタンスの Bullet スクリプトへの参照です。

BulletObject には以下の関数が含まれます。

  • WakeUp ― BulletPool によって、その Pop 関数が呼び出された時に呼び出されます。

  • Sleep ― BulletPool によって、その Push 関数が呼び出された時に呼び出されます。

  • ReturnToPool ― 特定の弾丸についての処理が必要なくなったときに呼び出されます。BulletPool の Push 関数を呼び出し、その結果として Sleep 関数を呼び出します。