Andengineでは画像を表示するならSprite、テキストならTextクラスのオブジェクトを生成します。
ですが、オブジェクトの生成は重くなるので、大量のオブジェクトを「必要になったら生成。不必要になったら削除。」といった処理で利用しているとFPSが落ちてしまいます。
このようなオブジェクトはAndengineのGenericPoolを使って再利用することで処理を軽くすることができます。
GenericPoolのイメージ
「Pool」とは泳ぐプールの他に「蓄える」といった意味があります。つまりGenericPoolはオブジェクトを蓄えておくのに利用するクラスということです。ここでは、Spriteをシューティングゲームの弾として使っている場合を考えます。
シューティングゲームの弾は画面上に沢山現れますが、その全てはすぐに画面外に出て行ったり、キャラクターに当たったりして画面から消えます。
このようなゲームでは弾のSpriteをGenericPoolで再利用する場合、以下のような処理になります。
- 弾を画面上から消す際に、そのSpriteのオブジェクトを削除せずに、GenericPoolに格納する。
- 次に、新しいが必要になった際に、新しいSpriteオブジェクトを生成せずに、GenericPoolに格納されているSpriteを取り出す。
- GenericPoolが空の時に弾が必要な場合は、GenericPoolにSpriteオブジェクトを作らせる。
ここで、プールに格納することをRecycle。プールから取り出すことをObtain。新しくオブジェクトを作ることをAllocateといいます。
![]() |
GenericPoolでの弾の再利用のイメージ |
GenericPoolの使い方
GenericPoolの準備
このくらいの処理なら、弾を管理するクラスを自作してしまっても良いのですが、「Generic」の名の通り、Sprite以外のあらゆるクラスのオブジェクトの再利用に使えます(ただし1つのプールには1種類のクラスのみ)。プログラムで書く必要があるのは
- プールに格納する時にオブジェクトに施す処理
- プールから取り出すときにオブジェクトに施す処理
- オブジェクトを生成する時にオブジェクトに施す処理
だけです。弾を蓄えるbulletPoolというオブジェクトを作ってみます。コードは以下のような感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //インポート文 import org.andengine.util.adt.pool.GenericPool; //プールの生成 GenericPool<sprite> bulletPool; bulletPool = new GenericPool<sprite>() { //オブジェクトを生成する処理 @Override protected Sprite onAllocatePoolItem() { return new Sprite( 0 , 0 , bulletTextureRegion, vbom); } //格納、または新たに生成されたオブジェクトを取り出すときに施す処理 @Override protected void onHandleObtainItem(Sprite pItem) { } //オブジェクトをプールに格納するときに施す処理 @Override protected void onHandleRecycleItem(Sprite pItem) { pItem.detachSelf(); pItem.reset(); pItem.setPosition( 0 , 0 ); pItem.clearEntityModifiers(); pItem.clearUpdateHandlers(); } }; } //あらかじめプールに100個オブジェクトを作っておく bulletPool.batchAllocatePoolItems( 100 ); |
GenericPoolを継承した新たなクラスを作らなくても、3つのメソッドをオーバーライドすれば良いです。また、batchAllocatePoolItemsで指定した個数のオブジェクトをプールに格納することができます。
オブジェクトの取り出し、格納
プールしたオブジェクトを得たい場合は準備したプールに対してobtainPoolItem()をします。 オブジェクトを格納したい場合はプールに対してrecyclePoolItem()をします。以下のような感じ。1 2 3 4 5 | //必要なときは Sprite bullet = bulletPool.obtainPoolItem(); //要らなくなったら bulletPool.recyclePoolItem(bullet); |
まとめ
格納、取り出し、生成をオーバーライドすればプールを簡単に用意できます。利用も簡単。
注意すべき点は、再利用前のオブジェクトの状態が残ってしまわないようにすることです。
リサイクルするオブジェクトは、再び利用されるまでにonHandleRecycleItem()とonHandleObtainItem()の処理を受けます。新たに生成されるオブジェクトは利用されるまでにonHandleObtainItem()の処理を受けます。
これらのメソッドを使って、再利用するオブジェクトをしっかり新品同様にするように注意しましょう。
逆に、何もせずとも新品同様ならonAllocatePoolItem()のオーバーライドのみでよいです。
また、頻繁に同じオブジェクトを生成、削除する場合はEntityに限らずModifierとかでも応用可能です。
注意すべき点は、再利用前のオブジェクトの状態が残ってしまわないようにすることです。
リサイクルするオブジェクトは、再び利用されるまでにonHandleRecycleItem()とonHandleObtainItem()の処理を受けます。新たに生成されるオブジェクトは利用されるまでにonHandleObtainItem()の処理を受けます。
これらのメソッドを使って、再利用するオブジェクトをしっかり新品同様にするように注意しましょう。
逆に、何もせずとも新品同様ならonAllocatePoolItem()のオーバーライドのみでよいです。
また、頻繁に同じオブジェクトを生成、削除する場合はEntityに限らずModifierとかでも応用可能です。
0 件のコメント:
コメントを投稿