- 追加された行はこの色です。
- 削除された行はこの色です。
有限状態機械の実装です
有限状態機械はある状態からある状態へ状態遷移をする仕組みです
ゲームなどではタイトルのシーンからゲームのシーンに移り変わるというように
シーンの状態を遷移をすることになります
また、キャラクターのAIなどの実装にも非常に有用です
今回はこれを実装します
&ref(state.jpg);
メンバ関数ポインタを使えばクラス内のメンバ関数に自由に飛び移れるような形で実装することができます
今回の全ファイル
zip:&ref(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;
}
実行結果は次のようになります
&ref(statemachine.jpg);
この仕組みを導入すれば
どのような状態遷移でもメンバ関数を追加することで柔軟に対応することができると思います
#vote(理解できた(^ω^)[0],なんぞこれーΣ(゚д゚lll)[0],ちょっと理解できないですね(´・ω・`)[0])
#vote(理解できた(^ω^)[7],なんぞこれーΣ(゚д゚lll)[3],ちょっと理解できないですね(´・ω・`)[4])