有限狀態機(FSM)學習總結C#


  FSM,有限狀態機,可以理解成是對行為邏輯的抽象,就好象人在生活中會做出各種行為,例如吃飯、睡覺等,這些所有我們都看作是“行為”的分支,由大腦決定每種行為具體是什么實施。在整個FSM架構中,其實與上面解釋一致,首先有一個狀態基類stateObject,里面有三個方法,分別是狀態前、狀態中、狀態后。所有具體行為都要繼承這個基類,在這三個方法中具體實現各種方法的邏輯。然后,需要一個stateManager(大腦)狀態管理類來管理這些狀態,特別注意的是里面changeState方法,他是狀態跳轉的關鍵。至於如果存儲各種狀態,你可以用list類 ,字典類等等。有限狀態機是把一個對象的行為分解稱為易於處理的“塊”或狀態。

   例如將人的行為抽象成3個,分別是吃飯、睡覺、上班。上班族,只有吃飯、睡覺、上班三種行為,我們把這三種行為放進我們的大腦,即stateManager。那我們從什么行為開始呢?(其實這里就是initState),隨便挑一個,默認為睡覺。之前說過,每個行為都有三個狀態(前、中、后),當我們進入睡覺行為時,首先進入的是睡覺前狀態(該狀態只執行一次),然后進入睡覺中,真正的邏輯是在這里執行的,它會不停檢查什么時候睡醒了,符合條件后跳到其他狀態,當要進行跳轉時,還會執行一次睡覺后狀態,其實前、后狀態我理解成當要執行或結束某種行為時,你要額外做的事情。例如,睡覺前我要帶個眼罩。(放到游戲開發里可以進行一些賦值操作,或者調用其他類的方法,例如一些特效)。因為它編程快速簡單,易於調試,性能高,與人類思維相似從而便於梳理,靈活且容易修改

  FSM的優點就是因為它編程快速簡單,易於調試,性能高,與人類思維相似從而便於梳理,靈活且容易修改。

以下是一個自己寫的實例代碼,可供大家參考

首先創建一個抽象狀態基類,里面有3個抽象方法,分別是進入狀態,離開狀態,更新狀態的方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class StateObject
{
    //狀態控制機
    protected StateManger sm;
    //構造函數
    public StateObject(StateManger _sm)
    {
        sm = _sm;
    }
    //進入狀態方法
    public abstract void EnterState();
    //離開狀態方法
    public abstract void ExitState();
    //更新狀態方法
    public abstract void UpdateState();



}

然后根據具體的情況創建具體的狀態類(繼承與狀態基類),我這里實現了3個具體的狀態類,分別是人物默認狀態,移動狀態,死亡狀態

默認狀態方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IdleState : StateObject
{
    public IdleState(StateManger _sm):base(_sm)
    {

    }
//進入狀態方法
    public override void EnterState()
    {
        Debug.Log("進入待定狀態");
    }
//離開狀態方法
    public override void ExitState()
    {
        Debug.Log("離開待定狀態");
    }
//更新狀態方法
    public override void UpdateState()
    {
        Debug.Log("更新待定狀態");
        if (Input.GetKeyDown(KeyCode.M))
        {
            sm.ChangeState("Move");
        }
        else if (Input.GetKeyDown(KeyCode.D))
        {
            sm.ChangeState("Die");
        }
       
    }

   
}

移動狀態方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveState : StateObject
{
    public MoveState(StateManger _sm) :base(_sm)
    {

    }
    public override void EnterState()
    {
        Debug.Log("進入移動狀態");
    }

    public override void ExitState()
    {
        Debug.Log("離開移動狀態");
    }

    public override void UpdateState()
    {
        Debug.Log("更新移動狀態");
        if (Input.GetKeyDown(KeyCode.D))
        {
            sm.ChangeState("Die");
        }
        else if(Input.GetKeyDown(KeyCode.I))
        {
            sm.ChangeState("Idle");
        }
    }
}

死亡狀態方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DieState : StateObject
{
    public DieState(StateManger _sm):base(_sm)
    {
       
    }
    public override void EnterState()
    {
        Debug.Log("進入死亡狀態");
    }

    public override void ExitState()
    {
        Debug.Log("離開死亡狀態");
    }

    public override void UpdateState()
    {
        Debug.Log("更新死亡狀態");
        if (Input.GetKeyDown(KeyCode.I))
        {
            sm.ChangeState("Idle");
        }
    }
}

然后,需要一個stateManager(大腦)狀態管理類來管理這些狀態,特別注意的是里面changeState方法,他是狀態跳轉的關鍵,需要放在Update函數中,因為需要不斷檢測當前的狀態,檢測是否跳轉

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StateManger {

    //利用字典存儲各種狀態
    Dictionary<string, StateObject> Dic = new Dictionary<string, StateObject>();

    //當前狀態
    StateObject currentstate;
    //注冊狀態
    public void Region(string statename,StateObject state)
    {
        if (!Dic.ContainsKey(statename))
        {
            Dic.Add(statename,state);
        }
    }

    //設置默認狀態
    public void SetDefat(string statename)
    {
        if (Dic.ContainsKey(statename))
        {
            currentstate = Dic[statename];
            currentstate.EnterState();
        }
    }
    //改變狀態
    public void ChangeState(string statename)
    {
        if (Dic.ContainsKey(statename))
        {
            if (currentstate!=null)
            {
                currentstate.ExitState();
                currentstate = Dic[statename];
                currentstate.EnterState();
            }
        }
    }

    //更新狀態
    public void UpdateState()
    {
        if (currentstate!=null)
        {
            currentstate.UpdateState();
        }
    }

}

這樣一個簡單的有限狀態機就寫好了,然后我們可以在Unity里面利用一個實例來測試一下,我寫了一個控制物體狀態的腳本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestFsm : MonoBehaviour {

//添加一個狀態機
    StateManger stm = new StateManger();
    void Start()
    {//注冊狀態
        stm.Region("Idle", new IdleState(stm));
        stm.Region("Die", new DieState(stm));
        stm.Region("Move", new MoveState(stm));
//設置默認狀態
        stm.SetDefat("Idle");
    }

    // Update is called once per frame
    void Update()
    {
//更新狀態的方法
        stm.UpdateState();
    }
}

  以上就是本人學習FSM的一點總結,如果有什么不對的地方,敬請大家指出,大家一起學習進步。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM