Unity/C# 有限狀態機

軒轅小羽發表於2018-01-18

遊戲中角色控制有很多狀態,如果靠傳統的全域性屬性然後通過swich和if來判斷的話,擴充套件性差,重複程式碼多.

通過編寫一個狀態管理庫來解決狀態變化的優點有

  • 程式碼整潔
  • 可複用
  • 易管理

什麼是有限狀態機?

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

Unity/C# 有限狀態機
如圖所示: 主角從跑狀態切換到跳狀態,從跳狀態切換到二段跳狀態,這裡的切換就是指狀態的轉移。狀態的轉移是有條件的,比如主角從跑狀態不可以直接切換到二段跳狀態。但是可以從二段跳狀態切換到跑狀態。

另外,一個基本的狀態有:進入狀態、退出狀態、接收輸入、轉移狀態等動作。但是僅僅作為跑酷的角色的狀態管理來說,只需要轉移狀態就足夠了。有興趣的同學可以自行擴充套件。

上程式碼

程式碼註釋很多,所以直接看程式碼配合註釋理解的更快

/*
 * 
 *      Title:
 *          狀態機/狀態管理庫
 *         
 *      Description:
 *          多種狀態切換,比傳統的 全域性引數+if/switch來切換狀態 更整潔和易擴充套件
 *          1.簡易狀態控制:通過新增狀態名稱,回撥方法. 呼叫改變狀態方法來回撥函式和引數.
 *          2.狀態機控制,通過新增幾種轉換的模式,再通過轉換行為來找到轉換後的狀態並執行方法.
 *      Date:
 *          2018年1月18日 12:48:13
 *        
 *      Modify Recoder:
 *          1.0
 *        
 */
namespace XYFramework
{

    using System.Collections.Generic;

    public class XYState
    {
        #region 引數
        /// <summary>
        /// 回撥函式
        /// </summary>
        /// <param name="param"></param>
        public delegate void XYCallbackFunc(params object[] param);
        /// <summary>
        /// 狀態名稱
        /// </summary>
        public string State { get; private set; }

        /// <summary>
        /// 儲存狀態回撥引數的字典
        /// </summary>
        private readonly Dictionary<string, XYSimpleStateModel> _simpleStateDict = new Dictionary<string, XYSimpleStateModel>();

        /// <summary>
        /// 儲存狀態機轉換StateModel用字典
        /// </summary>
        private readonly Dictionary<string, XYTranslationStateModel> _translateStateDict = new Dictionary<string, XYTranslationStateModel>();

        #endregion


        #region Model
        /// <summary>
        /// 記錄狀態名稱,和轉換XYTranslation物件
        /// </summary>
        class XYTranslationStateModel
        {
            private string _name;

            public XYTranslationStateModel(string name)
            {
                _name = name;
            }

            /// <summary>
            /// 記錄狀態名和轉換狀態物件的字典
            /// </summary>
            public readonly Dictionary<string, XYTranslateModel> TranslationDict = new Dictionary<string, XYTranslateModel>();
        }

        /// <summary>
        /// 簡易回撥資料模型
        /// </summary>
        public class XYSimpleStateModel
        {
            public string State;
            public XYCallbackFunc CallbackFunc;
            public XYSimpleStateModel(string state, XYCallbackFunc callBackFunc)
            {
                State = state;
                CallbackFunc = callBackFunc;
            }
        }

        /// <summary>
        /// 狀態轉換資料模型
        /// </summary>
        public class XYTranslateModel
        {
            public string FromState;
            public string Name;
            public string ToState;
            public XYCallbackFunc OnTranslationCallback;// 回撥函式

            public XYTranslateModel(string fromState,string name,string toState,XYCallbackFunc onTranslationCallback)
            {
                FromState = fromState;
                Name = name;
                ToState = toState;
                OnTranslationCallback = onTranslationCallback;
            }
        }


        #endregion


        #region 狀態控制方法
        /// <summary>
        /// 新增一個新狀態
        /// </summary>
        /// <param name="name">狀態名稱</param>
        public void AddState(string name)
        {
            _translateStateDict[name] = new XYTranslationStateModel(name);
        }

        /// <summary>
        /// 設定最開始的狀態
        /// </summary>
        /// <param name="name"></param>
        public void StartState(string name)
        {
            State = name;
        }

        /// <summary>
        /// 新增一種狀態,和回撥方法
        /// </summary>
        /// <param name="state">狀態名稱</param>
        /// <param name="callbackFunc">回撥方法</param>
        /// <param name="param">回撥引數</param>
        public void AddSimpleState(string state, XYCallbackFunc callbackFunc)
        {
            _simpleStateDict[state] = new XYSimpleStateModel(state, callbackFunc);
        }

        /// <summary>
        /// 新增一種轉換狀態監聽
        /// </summary>
        /// <param name="fromState">原來是那種狀態</param>
        /// <param name="name">轉換行為名稱</param>
        /// <param name="toState">轉換為那種狀態</param>
        /// <param name="callbackFunc">回撥方法</param>
        public void AddTranslateState(string fromState,string name,string toState, XYCallbackFunc callbackFunc)
        {
            _translateStateDict[fromState].TranslationDict[name] = new XYTranslateModel(fromState, name, toState, callbackFunc);
        }


        /// <summary>
        /// 改變狀態
        /// </summary>
        /// <param name="state">狀態名</param>
        /// <param name="param">引數</param>
        public void ChangeState(string state,params object[] param)
        {
            if (_simpleStateDict.ContainsKey(state) == false)
            {
                XYLog.LogError("未找到這個狀態");
                return;
            }
            XYSimpleStateModel simple = _simpleStateDict[state];
            simple.CallbackFunc(param);
            State = state;
        }

        /// <summary>
        /// 通過傳入事件名,自動轉換狀態
        /// </summary>
        /// <param name="name">轉換事件名稱</param>
        /// <param name="param">引數</param>
        public void TranslateState(string name,params object[] param)
        {

            if (State != null)
            {
                XYLog.LogError("未賦值初始狀態");
                return;
            }
            if (_translateStateDict[State].TranslationDict.ContainsKey(name))
            {
                XYLog.LogError("未找到這個轉換狀態");
                return;
            }
            XYTranslateModel tempTranslation = _translateStateDict[State].TranslationDict[name];
            tempTranslation.OnTranslationCallback(param);
            State = tempTranslation.ToState;
           
        }
        #endregion

        /// <summary>
        /// 清理這個例項的儲存
        /// </summary>
        public void Clear()
        {
            _translateStateDict.Clear();
        }

    }//class_end

}

複製程式碼

效果

Unity/C# 有限狀態機

中間還搭配使用了一個Log庫,感興趣的可以一起看一下

倉庫地址:https://github.com/Lafree317/XYFrameWork

相關文章