簡述遊戲開發中的狀態機

爲何咱們須要狀態機

實行較多狀態的角色,把動做全寫在一個部分中會致使維護成本高,拓展性低
例如:走路,跳躍,射擊,躲避的相互轉換,有些能夠轉換,有些不能,實現邏輯複雜
(滿屏幕都是if - else)併發

狀態模式switch實現

//包含着全部的狀態
enum class State{StateA, StateB, StateC, ...} activeState;
...
//經過switch語句切換狀態,根據具體狀況實現細節
switch (activeState)
{
    case State.StateA:
        ...
        break;
    case State.StateB:
        ...
        break;
    .......
}
...

狀態機的原形,用一個枚舉表示當前的狀態,經過填充完善switch語句實現狀態之間的切換,可是依然有維護成本高拓展低的缺點(雖然確實是比用if - else堆好)人工智能

Finite State Machine(FSN)有限狀態機

最基本的狀態機,通常來講其餘狀態機都是這種狀態機的變體
對於狀態機的理解,最好就是畫個圖(如圖結構,方框是狀態,箭頭是狀態之間的聯繫)code

有限狀態機強調的是狀態之間的切換,以及對不一樣狀態的封裝,因此實現方法通常能夠根據需求調整
如下參考了《遊戲人工智能》的實現
首先須要個基類State和基類Translation對象

//狀態基類,全部狀態都繼承這個類
class State
{
public:
    virtual ~State(){}
    virtual OnStateEnter(){}    //進入此狀態執行一次
    virtual OnUpdate(){}        //每一幀執行一次
    virtual OnStateExit(){}     //跳出狀態時調用一次
    list<Translation> translations; //狀態遷移列表
};

//狀態遷移
class Translation
{
public:
    virtual ~Translation(){}
    virtual bool isValid() = 0;         //用於斷定遷移,可切換返回true
    virtual State* getNextState() = 0;  //進入下一個狀態
    virtual void onTransition(){}       //遷移時調用
};

State是每個狀態都會繼承的基類,translations中存着他指向其餘狀態的Translation,經過每一幀遍歷全部Translation的isValid()來斷定是否能夠跳轉,若能夠跳轉則執行自身的OnStateExit(),並將當前的狀態設置爲getNextState()得到的狀態blog

而後還有狀態機類,用來管理全部狀態:繼承

//狀態機類
class FiniteStateMachine
{
public:
    void Update();          //每一幀運行一次
    State* initialState;    //初始狀態
    State* activeState;     //正在運行的狀態
    
protected:
    list<State> states;     //全部狀態的實例
};

void FiniteStateMachine::Update()
{
    //遍歷活動狀態的全部遷移,如有可用的,則切換狀態
    list<Translation>::iterator itr = activeState->translations.begin();
    for (int i = 0; i < activeState->translations.size(); ++i, ++itr)
    {
        if (itr->isValid())
        {
            activeState->OnStateExit();     //退出調用
            activeState = itr->getNextState();  //切換活動狀態
            itr->onTransition();                //切換調用
            activeState->OnStateEnter();    //進入調用
            return;                 //直接返回
        }
    }
    //若是沒有狀態切換,運行一次update
    activeState->OnUpdate();
}

接下來具體的狀態細節就要具體繼承,具體實現遊戲

Hierarchical Finite State Machine (HFSM) 分層狀態機

分層狀態機至關於對有限狀態機的進一步封裝,將複數個狀態封裝成一個大的狀態,再用一個「歷史狀態」記錄切出此狀態時運行的子狀態,就能夠在大狀態間切換(結構如圖)get

圖中將StateA和StateB加入到一個更高層的狀態StateD中,只需退出時記錄狀態,就能夠在CD狀態間切換,增長了狀態C的複用性(省略了AC,BC間的聯繫)
主要思想一是包裝更高的層次,二是高層的切換放到更高層來以爲以提升複用
分層狀態機的實現主要分兩種:
1、父狀態就是一個狀態機,能夠往裏面添加狀態
2、添加一個狀態棧儲存父子狀態,每個狀態都是棧下一個狀態的子狀態,進入狀態時入棧,結束狀態時出棧併發送一個消息,新棧頂狀態不能處理就再出棧,直到棧頂狀態能處理這個消息爲止。it

併發狀態機

併發狀態機能夠理解爲一個對象擁有兩個同時運做的狀態機,兩個狀態機相互獨立(但能夠經過修改對象的狀態進行通訊),例如咱們能夠將腿部動做(站立,下蹲,奔跑)和手部動做(持槍,空手,瞄準)分離。io

下推狀態機

下推狀態機的核心是他有一個狀態棧(但和層次狀態機實現的棧徹底不一樣,層次狀態機的棧是爲了記錄父狀態,這個棧是爲了紀錄上一個狀態)。
狀態棧主要解決的是狀態機沒法獲得上一輪執行的狀態。
實現時,在狀態機中加一個棧,在進入狀態時將狀態入棧,退出狀態時將狀態出棧,運行時則運行棧頂的狀態。
例如,我在作做業的時候餓了,想去吃東西。餓了去吃東西是多數狀態都能進入的狀態,而且結束「吃東西」的狀態後我要回復原來的狀態。

在運行時,狀態機已經將「作做業「入棧
而後「我餓了」,將「吃東西」入棧
「吃東西」結束,將「吃東西」出棧
繼續運行棧頂的「作做業」(事實上不可能)

如有錯誤,歡迎指出

相關文章
相關標籤/搜索