Unity狀態(tài)機

前言

眾所周知,Unity在開發(fā)游戲的時候經(jīng)常用到狀態(tài)機阅爽,而通常情況下挟伙,我們會使用簡單的枚舉類型設(shè)置狀態(tài)楼雹,然后通過調(diào)整枚舉,來切換狀態(tài)尖阔,在簡單情況下是可以的贮缅,就像是Unity中Animator切換動畫狀態(tài)就是,直接通過動畫片段的名稱切換诺祸。而當(dāng)狀態(tài)很多的時候携悯,直接切換就顯得有些很不安全祭芦,而且友好性也不是很好筷笨,所以根據(jù)Unity中Animator這種通過條件切換狀態(tài)的架構(gòu),我寫了一個簡單的狀態(tài)機龟劲,給大家分享胃夏。

  • 外部委托定義
    /// <summary>
    /// 狀態(tài)內(nèi)部事件委托
    /// </summary>
    public delegate void StateFunctionEventHandler();
    /// <summary>
    /// 狀態(tài)條件判斷委托
    /// </summary>
    public delegate bool StateTranslateEventHandler();
  • 狀態(tài)類
    /// <summary>
    /// 狀態(tài)類
    /// </summary>
    public class State {
        /// <summary>
        /// 狀態(tài)內(nèi)部事件
        /// </summary>
        public event StateFunctionEventHandler stateFunc;
        /// <summary>
        /// 狀態(tài)轉(zhuǎn)換事件<目標(biāo)狀態(tài),切換條件>
        /// </summary>
        public Dictionary<State,StateTranslateEventHandler> stateTrs;

        /// <summary>
        /// 狀態(tài)名稱
        /// </summary>
        /// <value>The name of the state.</value>
        public string stateName{get;private set;}

        /// <summary>
        /// 狀態(tài)運行中
        /// </summary>
        public bool isRun = false;

        /// <summary>
        /// 狀態(tài)內(nèi)部事件執(zhí)行間隔時間(毫秒)
        /// </summary>
        /// <value>The state function delta time.</value>
        public int stateFunctionDeltaTime{private get; set;}
        /// <summary>
        /// 狀態(tài)構(gòu)造
        /// </summary>
        /// <param name="name">Name.</param>
        public State(string name)
        {
            stateName = name;
            stateTrs = new Dictionary<State, StateTranslateEventHandler> ();
            stateFunctionDeltaTime = 200;
            Thread th = new Thread (Update);
            th.Start ();
        }

        /// <summary>
        /// 狀態(tài)內(nèi)部事件執(zhí)行
        /// </summary>
        public void Update()
        {
            while(true)
            {
                if(!isRun)
                {
                    continue;
                }

                Thread.Sleep (stateFunctionDeltaTime);
                if(stateFunc != null)
                {
                    stateFunc();
                }
            }
        }
        /// <summary>
        /// 注冊切換事件.
        /// </summary>
        /// <param name="target">目標(biāo)狀態(tài).</param>
        /// <param name="conditional">條件事件.</param>
        public void RegisterTranslate(State target, StateTranslateEventHandler conditional)
        {
            try
            {
                stateTrs.Add (target, conditional);
            }
            catch(Exception ex)
            {
                Debug.LogError(ex.ToString());
            }
        }
    }
  • 狀態(tài)管理類
    /// <summary>
    /// 狀態(tài)管理
    /// </summary>
    public class StateController : State {

        /// <summary>
        /// 狀態(tài)管理構(gòu)造
        /// </summary>
        /// <param name="name">Name.</param>
        public StateController(string name) : base(name)
        {
            states = new Dictionary<string, State> ();
            stateparams = new Dictionary<string, object> ();
            stateFunc += CheckTranslate;
            isRun = true;
            Thread mainTh = new Thread (Update);
            mainTh.Start ();
        }
        /// <summary>
        /// 狀態(tài)字典
        /// </summary>
        Dictionary<string,State> states;
        /// <summary>
        /// 狀態(tài)切換參數(shù)字典
        /// </summary>
        Dictionary<string,object> stateparams;
        /// <summary>
        /// 當(dāng)前狀態(tài)
        /// </summary>
        public State currentState;
        /// <summary>
        /// 添加狀態(tài)
        /// </summary>
        /// <returns>The state.</returns>
        /// <param name="statename">狀態(tài)名稱.</param>
        public State AddState(string statename)
        {
            State temp = new State (statename);
            states.Add (statename, temp);
            SetDefault (temp);
            return temp;
        }
        /// <summary>
        /// 添加狀態(tài)
        /// </summary>
        /// <param name="s">狀態(tài).</param>
        public void AddState(State s)
        {
            states.Add (s.stateName, s);
            SetDefault (s);
        }
        /// <summary>
        /// 移除狀態(tài)
        /// </summary>
        /// <param name="statename">狀態(tài)名稱.</param>
        public void RemoveState(string statename)
        {
            states.Remove (statename);
        }
        /// <summary>
        /// 設(shè)置默認(rèn)狀態(tài)
        /// </summary>
        /// <param name="s">S.</param>
        private void SetDefault (State s)
        {
            if(states.Count == 1)
            {
                currentState = s;
                s.isRun = true;
            }
        }
        /// <summary>
        /// 切換狀態(tài)
        /// </summary>
        /// <param name="name">狀態(tài)名稱.</param>
        public void TranslateState(string name)
        {
            if(states[name] != null)
            {
                currentState.isRun = false;
                currentState = states [name];
                states [name].isRun = true;
            }
        }
        /// <summary>
        /// 獲取狀態(tài)
        /// </summary>
        /// <returns>The state.</returns>
        /// <param name="statename">Statename.</param>
        public State GetState(string statename)
        {
            return states [statename];
        }

        /// <summary>
        /// 注冊參數(shù)
        /// </summary>
        /// <param name="paramName">參數(shù)名稱.</param>
        /// <param name="value">參數(shù)值.</param>
        public void RegisterParams(string paramName, int value)
        {
            stateparams.Add (paramName, value);
        }
        /// <summary>
        /// 注冊參數(shù)
        /// </summary>
        /// <param name="paramName">參數(shù)名稱.</param>
        /// <param name="value">參數(shù)值.</param>
        public void RegisterParams(string paramName, float value)
        {
            stateparams.Add (paramName, value);
        }
        /// <summary>
        /// 注冊參數(shù)
        /// </summary>
        /// <param name="paramName">參數(shù)名稱.</param>
        /// <param name="value">參數(shù)值.</param>
        public void RegisterParams(string paramName, string value)
        {
            stateparams.Add (paramName, value);
        }
        /// <summary>
        /// 獲取int類型參數(shù)
        /// </summary>
        /// <returns>The int parameters.</returns>
        /// <param name="paraName">Para name.</param>
        public int GetIntParams(string paraName)
        {
            return (int)stateparams [paraName];
        }
        /// <summary>
        /// 獲取float類型參數(shù)
        /// </summary>
        /// <returns>The float parameters.</returns>
        /// <param name="paraName">Para name.</param>
        public float GetFloatParams(string paraName)
        {
            return (float)stateparams [paraName];
        }
        /// <summary>
        /// 獲取string類型參數(shù)
        /// </summary>
        /// <returns>The string parameters.</returns>
        /// <param name="paraName">Para name.</param>
        public string GetStringParams(string paraName)
        {
            return (string)stateparams [paraName];
        }
        /// <summary>
        /// 設(shè)置int參數(shù)
        /// </summary>
        /// <param name="paraName">Para name.</param>
        /// <param name="value">Value.</param>
        public void SetIntParams(string paraName, int value)
        {
            stateparams[paraName] =value;
        }
        /// <summary>
        /// 設(shè)置float參數(shù)
        /// </summary>
        /// <param name="paraName">Para name.</param>
        /// <param name="value">Value.</param>
        public void SetFloatParams(string paraName, float value)
        {
            stateparams[paraName] =value;
        }
        /// <summary>
        /// 設(shè)置string參數(shù)
        /// </summary>
        /// <param name="paraName">Para name.</param>
        /// <param name="value">Value.</param>
        public void SetStringParams(string paraName, string value)
        {
            stateparams[paraName] =value;
        }
        /// <summary>
        /// 檢查狀態(tài)切換
        /// </summary>
        private void CheckTranslate()
        {
            foreach (var item in currentState.stateTrs) 
            {
                if(item.Value())
                {
                    TranslateState(item.Key.stateName);
                }
            }
        }
    }
  • 實例應(yīng)用
public class GameController : MonoBehaviour {

    //單例
    static StateController stateController;
    //外部測試
    public bool test = false;

    void Awake()
    {
        //1、實例化單例
        stateController = new StateController ("MainSc");
    }

    void Start()
    {
        //2昌跌、注冊狀態(tài)Idle
        State idle = stateController.AddState ("Idle");
        //2仰禀、注冊狀態(tài)Run
        State run = stateController.AddState ("Run");
        //3、注冊參數(shù)Speed,默認(rèn)值0
        stateController.RegisterParams ("Speed", 0f);
        //4蚕愤、idle內(nèi)部事件
        idle.stateFunc += () => {
            Debug.Log(idle.stateName);
        };
        //4答恶、run內(nèi)部事件
        run.stateFunc += () => {
            Debug.Log(run.stateName);
        };
        //5、切換事件Idle --> Run
        idle.RegisterTranslate (run, () => {
            if(stateController.GetFloatParams("Speed") > 0.5f)
            {
                return true;
            }
            return false;
        });
        //5萍诱、切換事件Run --> Idle
        run.RegisterTranslate (idle, () => {
            if(stateController.GetFloatParams("Speed") <= 0.5f)
            {
                return true;
            }
            return false;
        });
    }

    void Update()
    {
        if (test)
        {
            //6悬嗓、切換參數(shù),調(diào)整狀態(tài)
            stateController.SetFloatParams("Speed",1);
        }
        else
        {
            stateController.SetFloatParams("Speed",0);
        }
    }
}

結(jié)束語

這個工具類中用到了多線程的處理裕坊,其中各個狀態(tài)的線程是持續(xù)執(zhí)行的包竹,所以后期還會繼續(xù)改進(jìn),如果讀者朋友有哪些更好的建議和意見,歡迎評論周瞎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苗缩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子声诸,更是在濱河造成了極大的恐慌酱讶,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件双絮,死亡現(xiàn)場離奇詭異浴麻,居然都是意外死亡,警方通過查閱死者的電腦和手機囤攀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門软免,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人焚挠,你說我怎么就攤上這事膏萧。” “怎么了蝌衔?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵榛泛,是天一觀的道長。 經(jīng)常有香客問我噩斟,道長曹锨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任剃允,我火速辦了婚禮沛简,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斥废。我一直安慰自己椒楣,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布牡肉。 她就那樣靜靜地躺著捧灰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪统锤。 梳的紋絲不亂的頭發(fā)上毛俏,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音饲窿,去河邊找鬼煌寇。 笑死,一個胖子當(dāng)著我的面吹牛免绿,可吹牛的內(nèi)容都是我干的唧席。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼淌哟!你這毒婦竟也來了迹卢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤徒仓,失蹤者是張志新(化名)和其女友劉穎腐碱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掉弛,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡症见,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了殃饿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谋作。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖乎芳,靈堂內(nèi)的尸體忽然破棺而出遵蚜,到底是詐尸還是另有隱情,我是刑警寧澤奈惑,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布吭净,位于F島的核電站,受9級特大地震影響肴甸,放射性物質(zhì)發(fā)生泄漏寂殉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一原在、第九天 我趴在偏房一處隱蔽的房頂上張望友扰。 院中可真熱鬧,春花似錦晤斩、人聲如沸焕檬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兼呵,卻和暖如春兔辅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背击喂。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工维苔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人懂昂。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓介时,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子沸柔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理循衰,服務(wù)發(fā)現(xiàn),斷路器褐澎,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法会钝,類相關(guān)的語法,內(nèi)部類的語法工三,繼承相關(guān)的語法迁酸,異常的語法,線程的語...
    子非魚_t_閱讀 31,622評論 18 399
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 3,658評論 0 7
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗俭正。 張土汪:刷leetcod...
    土汪閱讀 12,743評論 0 33
  • “遠(yuǎn)處蔚藍(lán)天空下奸鬓,涌動著金色的麥浪,當(dāng)微風(fēng)帶著收獲的味道掸读,吹向我臉龐全蝶,我們曾在田野里歌唱......” ...
    陶宗海閱讀 748評論 0 2