unity 簡易有限狀態(tài)機(jī)實(shí)現(xiàn)

unity 簡易有限狀態(tài)機(jī)實(shí)現(xiàn)

在我們從事unity工作時(shí),有時(shí)候會(huì)面對復(fù)雜的狀態(tài)切換,最簡單的方法就是用if else 或者 switch 進(jìn)行狀態(tài)判斷,如果狀態(tài)少還好,但是當(dāng)狀態(tài)多達(dá)十幾個(gè)甚至幾十個(gè)的時(shí)候,我們的所要寫的代發(fā)就可能出現(xiàn)耦合、冗余甚至難以維護(hù)的情況。這時(shí)候設(shè)計(jì)一款有限狀態(tài)機(jī)FSM就可以幫我們輕松的搞定這些問題。

有限狀態(tài)機(jī),(Finite-state machine, FSM),又稱有限狀態(tài)自動(dòng)機(jī),簡稱狀態(tài)機(jī),是表示有限個(gè)狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)模型。簡單說就是控制對象的有限狀態(tài)間的轉(zhuǎn)換。

本人參考了 涼鞋 老師的QFramework的簡易狀態(tài)機(jī)

FSM主要實(shí)現(xiàn)功能:

  • State 的 添加/移除

  • 設(shè)置初始 State

  • 轉(zhuǎn)換相關(guān)State(current State -> next State,StateChaged) 配置/移除

  • State enter / exit 方法回調(diào)

  • State 轉(zhuǎn)換執(zhí)行邏輯觸發(fā),事件方法回調(diào),并更新State狀態(tài)

具體代碼如下:

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

namespace YFramework
{
  /// <summary>
  /// 簡易有限狀態(tài)機(jī)
  /// </summary>
  public class FSMLite
  {
    /// <summary>
    /// 狀態(tài)轉(zhuǎn)換傳入?yún)?shù)
    /// </summary>
    public delegate void FSMStateChaged(params object[] stateParams);
    /// <summary>
    /// 狀態(tài)
    /// </summary>
    public class FSMState
    {
      private string name;
      public readonly Dictionary<string, FSMTranslation> stateTranslations = new Dictionary<string, FSMTranslation>();
      public Action stateEnter;
      public Action stateExit;
      public FSMState(string name, Action stateEnter, Action stateExit)
      {
        this.name = name;
        this.stateEnter = stateEnter;
        this.stateExit = stateExit;
      }
    }
    /// <summary>
    /// 狀態(tài)轉(zhuǎn)換 保存轉(zhuǎn)換前和轉(zhuǎn)換后的狀態(tài)
    /// </summary>
    public class FSMTranslation
    {
      public string name;
      public string fromState;
      public string toState;
      public FSMStateChaged callBack;

      public FSMTranslation(string name, string fromState, string toState, FSMStateChaged callBack)
      {
        this.name = name;
        this.fromState = fromState;
        this.toState = toState;
        this.callBack = callBack;
      }
    }


    private readonly Dictionary<string, FSMState> mStates = new Dictionary<string, FSMState>();
    /// <summary>
    /// 當(dāng)前狀態(tài)
    /// </summary>
    public string State { get; private set; }
    /// <summary>
    /// 添加狀態(tài)
    /// </summary>
    public void AddState(string stateName, Action star = null, Action end = null)
    {
      mStates[stateName] = new FSMState(stateName, star, end);
    }
    /// <summary>
    /// 添加注冊狀態(tài)轉(zhuǎn)換
    /// </summary>
    public void AddTranslation(string translationName, string fromState, string toState, FSMStateChaged callBack)
    {
      if (mStates.ContainsKey(fromState))
        mStates[fromState].stateTranslations[translationName] = new FSMTranslation(translationName, fromState, toState, callBack);
      else
        Debug.LogError("Please Add FSMState:" + fromState);
    }
    /// <summary>
    /// 刪除狀態(tài)
    /// </summary>
    public void RemoveState(string stateName)
    {
      if (mStates.ContainsKey(stateName))
        mStates.Remove(stateName);
    }
    /// <summary>
    /// 刪除狀態(tài)轉(zhuǎn)換
    /// </summary>
    public void RemoveTraslation(string translationName,string stateName)
    {
      if (mStates.ContainsKey(stateName) && mStates[stateName].stateTranslations.ContainsKey(translationName))
      {
        mStates[stateName].stateTranslations.Remove(translationName);
      }
    }
    /// <summary>
    /// 設(shè)置初始狀態(tài)
    /// </summary>
    public void Star(string stateName)
    {
      if (mStates.ContainsKey(stateName))
        State = stateName;
      else
      {
        State = null;
        Debug.LogError(string.Format("FMSStates don't contains the star state '{0}'", stateName));
      }
    }
    /// <summary>
    /// 執(zhí)行狀態(tài)轉(zhuǎn)換
    /// </summary>
    public void StateChage(string translationName, params object[] mParams)
    {
      if (!string.IsNullOrEmpty(State) && mStates.ContainsKey(State) && mStates[State].stateTranslations.ContainsKey(translationName))
      {
        FSMTranslation translation = mStates[State].stateTranslations[translationName];
        translation.callBack(mParams);
        State = translation.toState;
        if (mStates[translation.fromState].stateExit != null)
          mStates[translation.fromState].stateExit();
        if (mStates[translation.toState].stateEnter != null)
          mStates[translation.toState].stateEnter();
      }
      else if (string.IsNullOrEmpty(State))
        Debug.LogError(string.Format("the Star State is null or you don't set the Star State", State));
      else if (!mStates.ContainsKey(State))
        Debug.LogError(string.Format("the state '{0}' have not added", State));
      else if (!mStates[State].stateTranslations.ContainsKey(translationName))
        Debug.LogError(string.Format("the current state doesn't have the event '{0}' action", translationName));
    }
    /// <summary>
    /// 清空狀態(tài)
    /// </summary>
    public void StateClear()
    {
      mStates.Clear();
    }
  }
}

測試代碼如下:

public void FSMTest()
  {
    //創(chuàng)建FSM 
    FSMLite lite = new FSMLite();
    string StateJump = "jump";
    string StateRun = "run";
    string StateDoubleJump = "doubleJump";
    string EventLand = "land";
    string EventTouchDown = "touchDown";
    string EventJump = "eventJump";
    FSMLite.FSMStateChaged playerRun = (mParams) =>
    {
      Debug.Log("PlayerRun ~");
    };
    FSMLite.FSMStateChaged playerFristJump = (mParams) =>
    {
      Debug.Log("Player Frist Jump ~");
    };
    FSMLite.FSMStateChaged playerDoubleJump = (mParams) =>
    {
      Debug.Log("Player Double Jump ~");
    };
    //添加State
    lite.AddState(StateRun,()=>  Debug.Log("Run Star"),()=> Debug.Log("Run End"));
    lite.AddState(StateJump, () => Debug.Log("Jump Star"), () => Debug.Log("Jump End"));
    lite.AddState(StateDoubleJump, () => Debug.Log("Double Jump Star"), () => Debug.Log("Double Jump End"));
    //配置State轉(zhuǎn)換
    lite.AddTranslation(EventLand, StateJump, StateRun, playerRun);
    lite.AddTranslation(EventLand, StateDoubleJump, StateRun, playerRun);
    lite.AddTranslation(EventTouchDown, StateRun, StateJump, playerFristJump);
    lite.AddTranslation(EventJump, StateJump, StateDoubleJump, playerDoubleJump);
    //設(shè)置初始State
    lite.Star(StateRun);
    //執(zhí)行轉(zhuǎn)換
    lite.StateChage(EventTouchDown, null);
}

代碼稍微有點(diǎn)多,功能的實(shí)現(xiàn)也比較簡單,希望有不足的地方大家可以留言,我會(huì)盡快改進(jìn)~

希望能對大家的學(xué)習(xí)生活有所幫助~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容