#概要
new しては 消して、 new しては 消してを繰り返すとgcがいっぱい走って遅くなってしまう!
そんなあなたにはぴったりの解決方法があります。
Poolを使って一度作ったオブジェクトを使い回そう!
#実際のユースケース
たとえば、武器の弾を実装するとき、「発射のときにnewして、ヒットしたら削除する 」みたいにつくるけど、
違いは座標以外だけで動作は同じだし、数は多いし、作っても数秒できえてしまう、はかなきオブジェクトを
うまいこと速度を落とさずうまい方法はないか・・。
#Pools
Libgdx側でPoolsが用意されていて、簡単に利用できます。
newしたときは直接つくらず、Pools.obtain(Class)でnewInstaceを作ってもらいます。
Classは引数なしのコンストラクタがないとダメかも。
そうするとPool内にそのインスタンスが登録されます。
弾がヒットした時など不必要になった時は、freeでもうつかってないよって教えてあげます。
そうすると次回Pools.obtain(Class)でnew Instanceを作る際はfreeの中のオブジェクトが返されて
新たにnewされません。(freeなものがあれば・・・。)
ただし、対象Classには、Pool.Poolable のインターフェイスの実装が必要です。
/** Resets the object for reuse. Object references should be nulled and fields may be set to default values. */
resetの時には不必要なメンバー変数をnullなどで参照をはずしましょう!
使いまわされたときに、変な挙動しないように。
abstract public class Pool<T> {
/** Objects implementing this interface will have {@link #reset()} called when passed to {@link #free(Object)}. */
static public interface Poolable {
/** Resets the object for reuse. Object references should be nulled and fields may be set to default values. */
public void reset ();
}
}
#使用例
(本家より一部改変)
public class Bullet implements Poolable {
public Vector2 position;
public boolean alive;
/**
* Bullet constructor. Just initialize variables.
*/
public Bullet() {
this.position = new Vector2();
this.alive = false;
}
/**
* Callback method when the object is freed. It is automatically called by Pool.free()
* Must reset every meaningful field of this bullet.
*/
@Override
public void reset() {
position.set(0,0);
alive = false;
}
//act(float delta)とかで玉の動きとか実装するけど割愛。最小限のみ
}
利用側
public class Unit {
//弾を打つ
public Bullet shoot(){
return Pools.obtain(Bullet.class);
}
//弾があたった時
public void hit(Bullet bullet){
Pools.free(bullet);
}
}
#資料
- 本家:Memory management : https://github.com/libgdx/libgdx/wiki/Memory-management
- Pools リファレンス : http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Pools.html