Hatena::Groupgamehell

ゲームプログラムめも日記 このページをアンテナに追加 RSSフィード

けんもほろろ  / オススメゲームプログラム本  / 作ったもの置き場  
ゲーム開発のデザパタまとめ  / めも日記まとめ  

2005-07-05

[]シーンの遷移(Stateパターン07:04 シーンの遷移(Stateパターン) - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - シーンの遷移(Stateパターン) - ゲームプログラムめも日記 シーンの遷移(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

タイトル>街>教会

教会から出る

タイトル>街

フィールドマップに移動

タイトルフィールドマップ

ダンジョンに潜る

タイトルフィールドマップダンジョン

↓戦闘シーン突入

タイトルフィールドマップ>ダンジョン>戦闘