ページ 11

アクションゲームにおける、ゲームオブジェクトのクラス設計について

Posted: 2016年2月27日(土) 15:20
by 質問者
現在、横スクロールアクション(マリオみたいなの)を制作中なのですが、ゲームオブジェクトのクラス設計(?)について悩んでいます。
考えた結果、以下の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();
		}
	}
}
 設計1の場合、ゲームオブジェクトすべてを種類を問わずObject型にキャストして1つの配列で管理できるのでコード量は減りますが、
          必ずObjectクラスの純粋仮想関数に沿って実装しなければならないので柔軟性に欠ける気がします。
          例えば追尾ミサイルなどを実装するとき、void Tracking(Object& target)という風に独自のメソッドを定義するとObject型の配列で扱うことができなくなると思います。

 設計2の場合、種類別に独自のメソッドを定義できるので柔軟性はあると思うのですが、クラスの型ごとに管理する配列を分ける必要があり、コード量がかなり増えてしまいます。


上に挙げた設計のうちどちらが良い設計といえるでしょうか?
それとも他に良いアイデアがありましたら教えてください。
しょうもない質問ですがよろしくお願いします。

Re: アクションゲームにおける、ゲームオブジェクトのクラス設計について

Posted: 2016年2月27日(土) 15:33
by hide
例えば追尾ミサイルなどを実装するとき、void Tracking(Object& target)という風に独自のメソッドを定義するとObject型の配列で扱うことができなくなる
そんなことはないです。
例えば安直ですが弾クラスに仮想関数としてMoveを持たせます。
そして、弾を継承する追尾ミサイルクラスのインスタンス生成時に追尾する対象の参照を持っておけば、Moveメソッドの実行時に参照できます。
あとはすべての生成された弾の配列にMoveを実行するだけです。
全クラスにUpdateメソッドという様にした場合でも考え方は同じです。

Re: アクションゲームにおける、ゲームオブジェクトのクラス設計について

Posted: 2016年2月28日(日) 11:25
by 質問者
座標更新用のメソッドに引数として直接渡すのではなく、初期化時に参照を持たせておくのですね!
参考になりました。ご回答ありがとうございます。