1. FSM 文中是用于改进复杂人工智能决策,除此之外,其实建立一个行为模型都可以用这个方法
2.行为模式是什么样的?拥有一个初始状态,根据输入,状态进行切换
3.可以看下 unity 中的动画状态机模块,他是图形界面的,更加的直观和容易理解
我们从 Entry 来看一下,这是入口状态,状态为Locomotion,他拥有两个可以选择转换的状态,一个是 vault,另一个是 Slide,由此我们可以看到,整个状态机的组成和每一个状态的组成
4. 组成:一个状态机管理器和有限个可以切换的状态,先从状态开始说,一个状态首先要声明自身的状态,以及可以进行切换的状态和切换这个状态需要的条件,来看下代码
状态:
class FSMState
{
public:
// 当前状态标记,以及所有状态切换的数量
FSMState(int StateID, unsigned usTransition, const char* sName);
~FSMState();
// 增加一个状态切换
void AddTransition(int iInput, int iOutput);
// 删除一个状态切换
void DeleteTransition(int iOutput);
// 根据输入条件获得输出状态
int GetOutput(int iInput);
public:
int GetID() { return m_iStateID; }
private:
// 所有可以进行转换的状态数量
unsigned m_usNumberOfTransistions;
// 所有的输入条件
int *m_pInputs;
// 所有的输出状态
int *m_pOutputs;
// 当前状态的标记
int m_iStateID;
public:
const char* GetName() { return m_sName; }
private:
const char* m_sName;
};
从代码中可以看出来,图中的切换箭头就是一个 Transition ,状态转移,它由两个部分组成,一个是转移条件,另一个是输出状态,也就是转移后的状态。
状态机管理:
class FSMClass
{
typedef std::map<int, FSMState*> STATE_MAP;
public:
// 构造给定初始化状态
FSMClass(int iStateID);
~FSMClass();
// 增加一个状态
void AddState(FSMState *pState);
// 删除一个状态
void DeleteState(int iStateID);
// 根据玩家数据(转移条件)进行状态转移
int StateTransition(int iInput);
public:
// 根据状态标记获得状态
FSMState * GetState(int iStateID);
// 获取当前状态
int GetCurrentState() { return m_iCurrentState; }
// 设置当前状态
void SetCurrentState(int iStateID) { m_iCurrentState = iStateID; }
private:
// 当前状态
int m_iCurrentState;
// 状态保存容器
STATE_MAP m_StateMap;
};
状态机管理器的作用,首先要保存所有可能的状态,其次需要记录当前的状态,这就相当于搭建出来了图中的架子,然后会提供一个触发状态转移的方法,一旦满足条件,就可以进行状态切换。
5. 使用
就使用来说,我们首先要创建状态机管理器并设置初始化状态,所有的状态和他们的状态切换以及状态切换条件,然后添加状态至管理器,设置初始状态
FSMState *pStateLocomotion = new FSMState(STATE_LOCOMOTION, 2, "Locomotion");
pStateLocomotion->AddTransition(INPUT_PLAYER_VAULT, STATE_VAULT);
pStateLocomotion->AddTransition(INPUT_PLAYER_SLIDE, STATE_SLIDE);
FSMState *pStateVault = new FSMState(STATE_VAULT, 1, "Vault");
pStateVault->AddTransition(INPUT_PLAYER_LOCOMOTION, INPUT_PLAYER_LOCOMOTION);
FSMState *pStateSlide = new FSMState(STATE_SLIDE, 1, "Slide");
pStateSlide->AddTransition(INPUT_PLAYER_LOCOMOTION, INPUT_PLAYER_LOCOMOTION);
FSMClass *pFSMClass = new FSMClass(STATE_LOCOMOTION);
pFSMClass->AddState(pStateLocomotion);
pFSMClass->AddState(pStateVault);
pFSMClass->AddState(pStateSlide);
std::cout << "当前状态:" << pFSMClass->GetState(pFSMClass->GetCurrentState())->GetName() << std::endl;
std::cout << "输入条件:" << "INPUT_PLAYER_VAULT" << std::endl;
pFSMClass->StateTransition(INPUT_PLAYER_VAULT);
std::cout << "当前状态:" << pFSMClass->GetState(pFSMClass->GetCurrentState())->GetName() << std::endl;
std::cout << "输入条件:" << "INPUT_PLAYER_LOCOMOTION" << std::endl;
pFSMClass->StateTransition(INPUT_PLAYER_LOCOMOTION);
std::cout << "当前状态:" << pFSMClass->GetState(pFSMClass->GetCurrentState())->GetName() << std::endl;
就是这样的一个流程