考えた結果、以下の2通りの設計を思いつきました。
1. Update()などの純粋仮想関数を用意した基底クラスを作り、それをプレイヤークラス、敵クラスなどに継承させ、実装させる方法
2. 基底クラスなしでクラスの種類に合わせて必要なメソッドを用意する方法
/* ======= 設計1の例 ======= */
class Object()
{
public:
Collision collision; //座標、大きさなどは Collisionクラスにまとめる
enum Type
{
player,
enemy,
block,
};
Type type; //オブジェクトの種類の選別に用いる
virtual void Update() = 0; //座標などの更新
virtual void HitProcess(Object& target) = 0; //衝突判定の処理
};
class Player : Object
{
Player()
{
/* 座標などの初期化 */
}
void Update()
{
/* 実際の処理 */
}
void HitProcess(Object& target)
{
bool IsHit = /* ターゲットと衝突しているかどうか */;
if (!IsHit) return;
if (target.type == Object::enemy)
{
/* ダメージを受ける */
}
if (target.type == Object::block)
{
/* 移動停止など */
}
}
};
class Enemy : Object
{
/* 省略 */
};
class Block : Object
{
/* 省略 */
};
/* ======= 設計2の例 ======= */
class Player
{
Collision collision;
void Update(); //座標更新
void Damage(); //ダメージを受ける
void Stop(); //止まる
};
class Enemy
{
Collision collision;
void Update() //座標更新
};
class Block
{
Collision collision;
};
int main()
{
/* 初期化 */
Player player; //プレイヤー
Enemy enemy; //敵
Block block; //ブロック
while (1) //メインループ
{
player.Update();
enemy.Update();
if (/* プレイヤーが敵と衝突していたら */)
{
player.Damage();
}
if (/* プレイヤーがブロックと衝突していたら */)
{
player.Stop();
}
}
}
必ずObjectクラスの純粋仮想関数に沿って実装しなければならないので柔軟性に欠ける気がします。
例えば追尾ミサイルなどを実装するとき、void Tracking(Object& target)という風に独自のメソッドを定義するとObject型の配列で扱うことができなくなると思います。
設計2の場合、種類別に独自のメソッドを定義できるので柔軟性はあると思うのですが、クラスの型ごとに管理する配列を分ける必要があり、コード量がかなり増えてしまいます。
上に挙げた設計のうちどちらが良い設計といえるでしょうか?
それとも他に良いアイデアがありましたら教えてください。
しょうもない質問ですがよろしくお願いします。