シーンの遷移(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的なフローになりがちです。
 
そこで、遷移が複雑になる場合には、
「シーンをスタックに積む」
という決まりを作ると、管理がやりやすくなります。
例)

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