天天看點

基于委托與事件的有限狀态機設計與實作(Unity3d)有限狀态機設計與實作

有限狀态機設計與實作

前言

其實在遊戲開發上,有限狀态機應用的方面還是很多,雖然現在有更好的解決方案,比如行為樹。但是簡單的說,有限狀态機更容易實作,在狀态比較少的情況下,使用有限狀态機顯得更直覺。但是在狀态過多的時候,使用有限狀态機就會使得狀态變得十分複雜,但是我認為有限狀态機在遊戲開發上又是比較基礎的東西,是以還是應該了解并掌握的。

什麼是有限狀态機?

有限狀态機,(英語:Finite-state machine, FSM),又稱有限狀态自動機,簡稱狀态機,是表示有限個狀态以及在這些狀态之間的轉移和動作等行為的數學模型。

狀态存儲關于過去的資訊,就是說:它反映從系統開始到現在時刻的輸入變化。轉移訓示狀态變更,并且用必須滿足來确使轉移發生的條件來描述它。動作是在給定時刻要進行的活動的描述。有多種類型的動作:

進入動作:在進入狀态時進行

退出動作:在退出狀态時進行

輸入動作:依賴于目前狀态和輸入條件進行

轉移動作:在進行特定轉移時進行

我自己對狀态機的了解就是,狀态機負責狀态的切換以及目前狀态的動作。

那麼這樣的話就可以設計一個狀态機負責角色的狀态切換以及執行狀态内的方法,多個狀态類需要有狀态的進入動作Enter,退出動作Exit以及執行的動作Action(轉移動作以後再說),還有一個角色類,通過角色類的動作來觸發狀态機的狀态切換來達到狀态的切換。

設計狀态機UML圖

基于委托與事件的有限狀态機設計與實作(Unity3d)有限狀态機設計與實作

大概是這樣的一個思路,這個圖有點舊就湊合着先用着了。

狀态機的設計思路

我是想遊戲的AI與玩家都能共用一套狀态機,這樣會不會比較友善一些,是以就給Player類跟AIEnemy類都設計了一個他們的基類AllCharacter類,接着是狀态機FiniteStateMachine類以及他們的狀态基類BaseState類。

AllCharacter.cs

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

public class AllCharacter : MonoBehaviour
{
    [HideInInspector]
    public BaseState CurBaseState;

    public enum StateType
    {
        //AI狀态
        STATE_PATROL,
        STATE_CHASE,
        //玩家狀态
        STATE_STAND,
        STATE_MOVE,
        //共同狀态
        STATE_ATTACK,
        STATE_DEAD,
    }

    public StateType CharaterState;
}
           

Player.cs

Player類中定義了一個委托PlayerStateChange和一個PlayerStateChange的事件StateChange,在Awake中注冊屬于Player的狀态
以及注冊狀态切換事件的方法ChangeState(在FiniteStateMachine中)
           
public class Player : AllCharacter
{
    public delegate void PlayerStateChange(AllCharacter.StateType stateType);
    public event PlayerStateChange StateChange;

    [HideInInspector]
    public FiniteStateMachine FsMachine;

    // Use this for initialization
    void Awake ()
    {
        FsMachine = new FiniteStateMachine(this);
        //注冊角色的狀态
        FsMachine.RegisterState(new AttackState(this));
        FsMachine.RegisterState(new StandState(this));
        FsMachine.RegisterState(new DeadState(this));
        FsMachine.RegisterState(new MoveState(this));
        //注冊事件
        StateChange+=new PlayerStateChange(FsMachine.ChangeState);
    }

    void Start()
    {
        //設定角色的初始狀态
        EnterStand();
    }

    void Update () {
        FsMachine.OnUpdate();
	}

    public void StickMove()
    {
        Debug.Log("Moving the JoyStick");
        StateChange(AllCharacter.StateType.STATE_MOVE);
    }

    public void DownAttack()
    {
        Debug.Log("Down the Attack");
        StateChange(AllCharacter.StateType.STATE_ATTACK);
    }

    public void EnterStand()
    {
        StateChange(AllCharacter.StateType.STATE_STAND);
    }
    }
           

Player中的方法StickMove()、DownAttack()是通過EasyTouch操作調用的,通過這兩個方法的調用可以控制角色狀态的切換

BaseState.cs

public class BaseState
{
    //擷取角色
    public AllCharacter Character;
    
    //得到目前狀态
    public virtual AllCharacter.StateType GetStateType()
    {
        return Character.CharaterState;
    }
    //進入狀态
    public virtual void EnterState(FiniteStateMachine fsMachine, BaseState preState)
    {

    }
    //狀态更新
    public virtual void UpdateState()
    {

    }
    //狀态結束 退出狀态
    public virtual void ExitState(BaseState preState)
    {

    }
    //輸入控制
    public virtual void InputHandle()
    {

    }

}
           

MoveState.cs

這是其中一個狀态類,負責角色移動時的動作

public class MoveState : BaseState
{
    private readonly Player _player;
    public MoveState(Player player)
    {
        this._player = player;
    }
    public override AllCharacter.StateType GetStateType()
    {
        return AllCharacter.StateType.STATE_MOVE;
    }
    public override void EnterState(FiniteStateMachine fsMachine, BaseState preState)
    {
        if (preState != null)
        {
            Debug.Log("Enter the MoveState the preState is:" + preState.GetStateType());
        }
        else
        {
            Debug.Log("Enter the MoveState");
        }
        //Debug.Log(_player.CurBaseState);
    }

    public override void UpdateState()
    {
        Debug.Log("I'm Moving.");
    }

    public override void ExitState(BaseState preState)
    {
        Debug.Log("Exit Move State. " + preState.GetStateType());
    }

    public override void InputHandle()
    {

    }
}
           

總結

其實有限狀态機蠻簡單的,也很基礎的東西,就是可以了解為Player在把在目前的狀态類執行的方法告訴狀态機,接着狀态機根據這個方法幫Player切換Player的狀态,接着再執行該狀态類的方法。要是以上有說得不妥的地方,希望幫忙指正一下,謝謝。