現在、C#(XNA)にてシューティングゲーム開発をしている天空橋光と申します。
シューティングゲームを作る際に、敵、弾、パーティクル、アイテムなどが
多量に出るゲームデザインを考えているため、絶えずnewを行うと
非常にパフォーマンスが悪い、またはGC発生率が高くなるため、
最初にこれらのオブジェクトを以下のようにプールすることにしました。
// プールを作成
void init() {
for (int i = 0; i < 20000; i++) {
GameObject o = new GameObject();
pool.Push(o);
}
}
// プールよりオブジェクトを取得
GameObject createGameObject() {
return cache.Pop();
}
// 利用が終わったオブジェクトをプールに戻す
void deleteGameObject(GameObject o) {
cache.Push(o);
}
問題が一つ発生しました。
ゲームが大きくなると、敵の種類、弾の種類などが増えGameObjectという一つのクラスでは
データを共通管理するのが困難になってきたのです。
例えば以下のようケースだと、座標や体力などは、ある程度共通に取り扱える。
しかし、ある敵は羽を持っているので、羽を広げるまでの時間を管理する必要があるとかいった場合、
その敵特有の変数を持つ必要がある。
class GameObject {
////// 以下のものは十分共通として利用できる
// 各種座標データ
public float x;
public float y;
public float z;
// 体力データ
public hp;
////// 以下のようなものは共通として利用することは無い
// 羽を管理するための変数郡
public int wingStartTime;
public int wingCloseTime;
}
とりあえず、現在私が行った対応は以下のような、汎用変数を作ることで回避してみました。
class GameObject {
////// 以下のものは十分共通として利用できる
// 各種座標データ
public float x;
public float y;
public float z;
// 画面に登場してからの経過時間
public time;
////// 各固有のデータについては以下の変数を利用する
// 汎用変数
public int[] iVal = new int[10];
public float[] fVal = new float[10];
}
// 実際に利用する場合は以下のように利用
void actionWingEnemy(GameObject o) {
int wingStartTime = o.iVal[0];
int wingEndTime = o.iVal[1];
if (wingStartTime == time) {
// 羽を広げる
} else if (wingEndTime == time) {
// 羽を閉じる
}
}
そこで質問なのですが、C#でオブジェクトプールをどのように行うのが良いのか教えていただけないでしょうか?
または、そもそも、考え方かなにかがが間違っていたりするのでしょうか?
(例えばオブジェクトプールとかする必要ないよね?・・・とか)
なお、自分なりに考えた、他の対策には以下のようなものがあります。
他の案1.
敵ごとにWingGameObjectやNormalGameObjectのようにクラスを作製し、それごとにプールを作製する。
他の案1に対する個人的考察.
各ステージにおけるアイテム数などを個別に設定する必要があり非常に面倒
他の案2.
C++とかで、mallocで最初にメモリを一定量確保し、new演算子をオーバーロードして、確保したメモリからインスタンスを生成する
のと同等なことをC#でもしてみる。
他の案2に対する個人的考察.
C#だと、そもそも実現不可能?