游戏编程精粹(一) 有限状态机FSM

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;


就是这样的一个流程

猜你喜欢

转载自blog.csdn.net/weixin_42561030/article/details/80947054