シーン管理 コーディング
昨日のシーン管理、何のためか言ってなかった。
何のためかというと、つまりはゲームプログラミングにおけるシーン管理なんだけど。
日記タイトル見れば分かるか。すんません。
さて、今回は長いぞう。
実際にシーン管理のコーディングを泥沼でやってみたから。
シーン管理クラス
とりあえず何より、扱うものの細部よりも扱い方を決めたほうが設計が楽だ。(と自分は信じている。)
というわけでシーン管理クラスを作るわけだね。
実装は前の日記で、スタック付オートマトン*1で実装することに軍曹が決めたからその通りにする。
さて、シーン管理クラスの仕事はシンプルだ。
- シーンを登録する
- シーンを破棄する
- シーンを実行する
あと、仕事の進み具合も報告してほしい。つまり次の機能もほしい。
- シーンが全て無くなったか調べる
こんなところだろうかね。
それでは、仕様は大体まとまったので早速クラス宣言部を書く。
#include <stack> #include "IGameScene.h" // シーンを扱うからインクルード class SceneController{ public: SceneController(); ~SceneController(); void regist(IGameScene* gs); // シーン登録 void unregist(); // シーン削除 void act(); // シーン実行 bool empty(); // シーンが空っぽかどうか private: std::stack<IGameScene*> sceneStack; // シーンを積むスタック };
そして、シンプルな実装。
void SceneController::regist(IGameScene* gs){ gs->init(); sceneStack.push(gs); } void SceneController::unregist(){ sceneStack.top()->fin(); sceneStack.pop(); } void SceneController::act(){ if(!empty()){ sceneStack.top()->play(); } } bool SceneController::empty(){ return sceneStack.empty(); }
実装は非常にシンプルだが、コーディングの途中でいくつか決定したことがある。
- シーンの登録時、初期化を自動で行う。
- シーンを削除するときは、後処理を自動で行う。
- シーンの初期化関数名はinit()
- シーンの後処理関数名はfin()
- シーンの実行関数名はplay()
まぁ、とりあえず使うときはこんな感じだろう。まだシーンの実体を定義していないのでどうしようもないが。
…… SceneController *sc = new SceneController(); IGameScene *somescene = new SomeScene(sc); sc->regist(somescene); while(!sc->empty()){ sc->act(); } delete somescene; delete sc; ……
シーンインターフェイス
シーンの外部から見た仕事は決まっている。すなわち
- 初期化
- 実行
- 後処理
である。よってこの3つの関数を持つインターフェイスを作る。
さらに、シーンは他のシーンを登録する操作もありえる。
ゆえに、シーン管理クラスへのポインタも保持することにする。
簡単に言えば、上司(自分を管理する人)の連絡先を覚えとく。
このほうが色々都合が良い。
これをコードで表現すればこうなる。
class SceneController; // クラスの前方宣言、これは便利だ! class IGameScene{ public: IGameScene(SceneController *sc):sc(sc){} // 全て純粋仮想関数 virtual ~IGameScene(){}; virtual int init() = 0; // 初期化 virtual int play() = 0; // 実行 virtual int fin() = 0; // 後処理 protected: SceneController *sc; // 管理者の連絡先 };
インターフェイスだからメンバ関数は全て純粋仮想関数に(virtual & 0で初期化)してある。
そして、次に実際にシーンを定義する。
のだが、長いのでまた次回。