有限状態機械の実装です
有限状態機械はある状態からある状態へ状態遷移をする仕組みです
ゲームなどではタイトルのシーンからゲームのシーンに移り変わるというように
シーンの状態を遷移をすることになります
また、キャラクターのAIなどの実装にも非常に有用です
メンバ関数ポインタを使えばクラス内のメンバ関数に自由に飛び移れるような形で実装することができます
今回の全ファイル
zip:statemachine.zip
以下に有限状態機械クラスの実装を示します
任意のクラスのメンバ関数のポインタを変数として持つStateMachineクラスを作ります
コンストラクタでは必ず、開始となるメンバ関数を登録しなければなりません
処理実行後、次の処理を行うメンバ関数のポインタを戻り値として受取ります
statemachine.h
// シーン内遷移を行うテンプレートクラス // メンバ関数ポインタによる実装 #pragma once template <typename T> class StateMachine { public: StateMachine( StateMachine<T> (T::*f)() ) : func_( f ) {}; StateMachine<T> Exe( T* obj ) { return (obj->*func_)(); // 現在のメンバ関数を実行して、StateMachineクラスのオブジェクトを返す } private: StateMachine<T> (T::*func_)(); // Tクラスメンバ関数ポインタ };
実装例は次のようになります
注目して欲しいのはmain関数ではExecuteメンバ関数しか呼んでいない点です
main.cpp
#include "statemachine.h" #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <windows.h> class GameFramework { private: // 自分のクラスのテンプレート型の有限状態機械を作る typedef StateMachine<GameFramework> STATE; // 長ったらしいのでtypedefで省略型作る STATE m_State; // 自分のクラスのメンバ関数ポインタを戻り値に返す STATE TitleScene(){ printf("タイトルシーンです\n"); return &GameFramework::GameScene;// 次に実行したいメンバ関数のポインタを渡す } STATE GameScene(){ printf("ゲームシーンです\n"); if(rand() % 2 == 0){ return &GameFramework::GameOverScene; } return &GameFramework::EndingScene; } STATE GameOverScene(){ printf("ゲームオーバーシーンです\n"); return &GameFramework::TitleScene; } STATE EndingScene(){ printf("エンディングシーンです\n"); return &GameFramework::TitleScene; } public: // コンストラクタ GameFramework():m_State(&GameFramework::TitleScene){} // デストラクタ virtual ~GameFramework(){} void Execute(){ m_State = m_State.Exe(this); } }; int main() { GameFramework game; while(true){ // 処理が早すぎるので1秒休む Sleep(1000); // ゲーム実行 game.Execute(); // キー入力でループ抜ける if(_kbhit()) break; } return 0; }
この仕組みを導入すれば
どのような状態遷移でもメンバ関数を追加することで柔軟に対応することができると思います