それでは実際にシーン管理システムを作っていきましょう。
まずswitch-case文の際にも必要になった4つの関数を関数ポインタとして定義しましょう。
SceneManager.h
// 初期化用関数 using InitFunc = bool (*)(void); // 解放用関数 using FinalFunc = void (*)(void); // 更新用関数 using UpdateFunc = void (*)(void); // 描画用関数 using RenderFunc = void (*)(void);
これで4つのベースとなる関数の定義が出来ました。
InitFunc以外は全て同じ型なので同じでも大丈夫なのですが、用途が違うので今回は別々に定義しています。
次に管理するための構造体を作成します。
// シーン処理設定用構造体 struct SceneProc { const char* Name; InitFunc Init; FinalFunc Final; UpdateFunc Update; RenderFunc Render; }; // シーン遷移用の関数型 using SetupFunc = SceneProc (*)(void);
SceneProc構造体はシーンごとの必要な関数を保持する構造体です。
1シーンにつき1構造体があれば事足りることになります。
ちなみにNameはオマケなので無くても大丈夫です。
今回はシーン名を保持させるために持たせていますがお好みでどうぞ。
SetupFuncについては次に出てきますが、シーン遷移を楽にするための関数を定義しています。
では次にシーン管理システムの実装を行っていきます。
// シーン管理の初期化 void InitializeSceneManager(void); // シーン管理の解放 void FinalizeSceneManager(void); // シーンの更新 void UpdateSceneManager(void); // シーンの描画 void RenderSceneManager(void); // シーンの遷移 bool JumpScene(SetupFunc Func); // シーン名の取得 const char* GetSceneName(void);
シーン管理システムも基本の4つの処理が必要となります。
そしてシーンの遷移関数とオマケのシーン名取得処理があります。
次に実装部分です。
SceneManager.cpp
#include "SceneManager.h" // 現在のシーン情報保持用 static SceneProc g_currentScene; // シーン管理の初期化 void InitializeSceneManager(void) { ZeroMemory(&g_currentScene, sizeof(g_currentScene)); } // シーン管理の解放 void FinalizeSceneManager(void) { // 最後は解放して終わる if( g_currentScene.Final ) g_currentScene.Final(); ZeroMemory(&g_currentScene, sizeof(g_currentScene)); } // シーンの更新 void UpdateSceneManager(void) { if( g_currentScene.Update ) g_currentScene.Update(); } // シーンの描画 void RenderSceneManager(void) { if( g_currentScene.Render ) g_currentScene.Render(); }
基本の処理はこの通りです。
管理用の構造体を初期化したのちに現在のセットされている処理があれば更新と描画の処理を呼び出すようになっています。
これで関数ポインタに対して関数さえ渡してしまえば勝手に関数を呼び出してくれるようにできます。
次にシーンの遷移処理です。
// シーンの遷移 bool JumpScene(SetupFunc Func) { // 現在のシーンを解放する if( g_currentScene.Final ) g_currentScene.Final(); ZeroMemory(&g_currentScene, sizeof(g_currentScene)); bool ret = true; // 次のシーンがあれば初期化する if( Func ) { g_currentScene = Func(); if( g_currentScene.Init ) ret = g_currentScene.Init(); } return ret; } // シーン名の取得 const char* GetSceneName(void) { if( g_currentScene.Name ) return g_currentScene.Name; return "Unknown"; }
JumpSceneでは下記の手順でシーンの切り替えを行っています。
- 現在のシーンを解放
- シーン情報のリセット
- SetupFunc型で渡された関数ポインタを実行して次のシーンの情報取得
- 次のシーンの初期化
手順としてはこんな感じになっています。
ここまで来たらある程度はどうやって実装するのか予想できた人も多いと思います。
では次のページで実際にシーンを作っていきましょう。