ゲーム開発のためのオブジェクト指向(State)

投稿者: | 2012年5月30日

はじめに

今回はデザインパターンのStateパターンを使って、シーンの遷移を実装してみようと思います。

ゲームには、

  • タイトル
  • モードセレクト
  • メインゲーム
  • 結果

などのシーンがあります。それらのシーンの遷移をオブジェクト指向で実現する方法を解説します。

シーンクラス

まず基底となるISceneクラスを定義します。

/**
 * シーン基底クラス
 */
class IScene
{
public:
	IScene();
	virtual ~IScene();
	virtual void Render() = 0; // シーンの描画
};

virtual void Render() = 0;

っていうのが、仮想関数の宣言で、この宣言によりISceneは仮想クラスになります。

そしてこれを継承して、各シーンクラスを実装します。

/**
 * タイトルシーン(タイトル画面)
 */
class CSceneTitle : IScene
{
public:
	CSceneTitle();
	~CSceneTitle();
	void Render();
};
シーンを使うクラス

そして、このシーンを利用するCGameクラスを定義します。

/**
 * ゲーム管理クラス。
 */
class CGame
{
private:
	static CGame m_singleton;
	static IScene *m_pScene; // シーンオブジェクト
	CGame();
	~CGame();
public:
	// シーン列挙型
	enum __SCENE
	{
		TITLE,       // タイトル画面
		MODE_SELECT, // モードセレクト画面
		GAME_MAIN,   // ゲームメイン画面
		RESULT,      // 結果画面
	};
	static void ChangeScene(__SCENE scene); // シーンの遷移
	static void Render(); // シーンの描画
};

CGameはゲームを管理するオブジェクトで、1つだけ存在すればよいのでシングルトンにし、スタティック関数のみで構成します。

CGame::Render()は、保持しているシーンオブジェクトのRender()を呼びます。

void CGame::Render()
{
	m_pScene->Render();
}

シーン遷移のCGame::ChangeScene()は、例えば以下のように実装します。

void CGame::ChangeScene(__SCENE scene)
{
	static CSceneTitle title;
	static CSceneModeSelect mode_select;
	static CSceneGameMain game_main;
	static CSceneResult result;

	switch(scene)
	{
	case TITLE:
		m_pScene = &title;
		break;
	case MODE_SELECT:
		m_pScene = &mode_select;
		break;
	case GAME_MAIN:
		m_pScene = &game_main;
		break;
	default: //case RESULT:
		m_pScene = &result;
		break;
	}
}

そうすると、シーンを遷移するときは、

// タイトル画面に遷移
CGame::ChangeScene(CGame::TITLE);

といった感じで、いつでもシーンオブジェクトを入れ替えられますね。

このような設計を、「状態」(ここではシーン)の変化により、「状態」をあらわすクラスをごっそり入れ替えることから、Stateパターンと呼びます。

補足

ゲームの規模によっては、シーンの遷移が複雑になることがあります。今回のような方法は、シーンをjump,jumpするようなものでgoto的なフローになりがちです。

そこで、遷移が複雑になる場合には、「シーンをスタックに積む」という決まりを作ると、管理がやりやすくなります。

例)
<strong>></strong>
↓タイトルをPush
><strong>タイトル</strong>
↓セーブデータセレクトをPush
>タイトル<strong>>セーブデータセレクト</strong>
↓セーブデータセレクトをPopして、セーブポイントの街と教会をPush
>タイトル<strong>>街>教会</strong>
↓教会から出る
>タイトル>街
↓フィールドマップに移動
>タイトル<strong>>フィールドマップ</strong>
↓ダンジョンに潜る
>タイトル>フィールドマップ<strong>>ダンジョン</strong>
↓戦闘シーン突入
>タイトル>フィールドマップ>ダンジョン<strong>>戦闘</strong>