日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

U3D-FSM有限状态机的简单设计

發(fā)布時間:2023/12/10 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 U3D-FSM有限状态机的简单设计 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://coder.beitown.com/archives/592

在之前的文章里介紹了一個基礎U3D狀態(tài)機框架(Unity3D游戲開發(fā)之狀態(tài)流框架)即大Switch的枚舉狀態(tài)控制。這種方法雖然容易理解,編程方法也相對簡單,但是弊端是當狀態(tài)變得復雜之后,或需要添加一種新的狀態(tài)時,會顯得非常混亂并且難以下手。故我們需要引進一種更高級的狀態(tài)機技術來避免這些問題。網(wǎng)上有一些講述U3D-FSM狀態(tài)機的文章,但都不針對基礎講解,而且大多帶有冗余的與狀態(tài)機不相關的代碼,基礎不好的讀者容易看不清FSM狀態(tài)機的核心所在。這里針對網(wǎng)上的一些文章和代碼做了一個整理,意圖使之簡單易懂。

這里關于FSM有限狀態(tài)機這類名詞的解釋這里就不再說明了,感興趣的朋友可以自己去百度下(度娘鏈接),本文只說重點。

首先是狀態(tài)機基類State.cs

/*** 狀態(tài)基類 */ public class State[entity_type> {public entity_type Target;//Enter state public virtual void Enter (entity_type entityType){}//Execute statepublic virtual void Execute (entity_type entityType){}//Exit statepublic virtual void Exit (entity_type entityType){}}

基類之所以設計成含有3個小的狀態(tài)方法是因為,通常在游戲中有些行為都只是在進入或退出某個狀態(tài)時出現(xiàn)的,并不會發(fā)生在通常的更新步驟中。這樣設計就可以有效的將持續(xù)性調(diào)用語句和一次性調(diào)用語句有效的區(qū)分開來。(舉例:發(fā)送技能時的特效,有些是持續(xù)性而有些又是一次性的)

接下來我們編寫狀態(tài)機代碼,來使直接的這個基類的各個方法運作起來:

using UnityEngine; using System.Collections;public class StateMachine[entity_type> {private entity_type m_pOwner;private State[entity_type> m_pCurrentState;//當前狀態(tài)private State[entity_type> m_pPreviousState;//上一個狀態(tài)private State[entity_type> m_pGlobalState;//全局狀態(tài)/*狀態(tài)機構造函數(shù)*/public StateMachine (entity_type owner){m_pOwner = owner;m_pCurrentState = null;m_pPreviousState = null;m_pGlobalState = null;}/*進入全局狀態(tài)*/public void GlobalStateEnter(){m_pGlobalState.Enter(m_pOwner);}/*設置全局狀態(tài)*/public void SetGlobalStateState(State[entity_type> GlobalState){m_pGlobalState = GlobalState;m_pGlobalState.Target = m_pOwner;m_pGlobalState.Enter(m_pOwner);}/*設置當前狀態(tài)*/public void SetCurrentState(State[entity_type> CurrentState){m_pCurrentState = CurrentState;m_pCurrentState.Target = m_pOwner;m_pCurrentState.Enter(m_pOwner);}/*Update*/public void SMUpdate (){if (m_pGlobalState != null)m_pGlobalState.Execute (m_pOwner);if (m_pCurrentState != null)m_pCurrentState.Execute (m_pOwner);}/*狀態(tài)改變*/public void ChangeState (State[entity_type> pNewState){if (pNewState == null) {Debug.LogError ("can't find this state");}//觸發(fā)退出狀態(tài)調(diào)用Exit方法 m_pCurrentState.Exit(m_pOwner);//保存上一個狀態(tài) m_pPreviousState = m_pCurrentState;//設置新狀態(tài)為當前狀態(tài)m_pCurrentState = pNewState;m_pCurrentState.Target = m_pOwner;//進入當前狀態(tài)調(diào)用Enter方法 m_pCurrentState.Enter (m_pOwner);}public void RevertToPreviousState (){//切換到前一個狀態(tài) ChangeState (m_pPreviousState);}public State[entity_type> CurrentState (){//返回當前狀態(tài)return m_pCurrentState;}public State[entity_type> GlobalState (){//返回全局狀態(tài)return m_pGlobalState;}public State[entity_type> PreviousState (){//返回前一個狀態(tài)return m_pPreviousState;}}

這個狀態(tài)機其實還不是最簡的,全局和上一個狀態(tài)的相關部分都可以去掉,但同時功能上就會被削減,故這里將其保留。

現(xiàn)在狀態(tài)基類和狀態(tài)機類都有了,我們可以開始編寫游戲對象的獨立狀態(tài)類,先編寫游戲的總流程狀態(tài)類,這里命名為MainState.cs

/*** 全局狀態(tài)*/ public class MainState : State[Main> {public static MainState instance;/*構造函數(shù)單例化*/public static MainState Instance(){if (instance == null)instance = new MainState();return instance;}public override void Enter(Main Entity){//這里添加進入此狀態(tài)時執(zhí)行的代碼 }public override void Execute(Main Entity){//這里添加持續(xù)此狀態(tài)刷新代碼 }public override void Exit(Main Entity){//這里添加離開此狀態(tài)時執(zhí)行代碼 }}/*** Ready狀態(tài)*/ public class MainState_Ready : State[Main> {public static MainState_Ready instance;/*構造函數(shù)單例化*/public static MainState_Ready Instance(){if (instance == null)instance = new MainState_Ready();return instance;}public override void Enter(Main Entity){//這里添加進入此狀態(tài)時執(zhí)行的代碼 }public override void Execute(Main Entity){//這里添加持續(xù)此狀態(tài)刷新代碼//這里是重點 當滿足某條件后 我們可以進行狀態(tài)切換 執(zhí)行如下代碼 切換到 Run狀態(tài) Entity.GetFSM().ChangeState(MainState_Run.Instance()); }public override void Exit(Main Entity){//這里添加離開此狀態(tài)時執(zhí)行代碼 } }/*** Run狀態(tài)*/ public class MainState_Run : State[Main> {public static MainState_Run instance;/*構造函數(shù)單例化*/public static MainState_Run Instance(){if (instance == null)instance = new MainState_Run();return instance;}public override void Enter(Main Entity){//這里添加進入此狀態(tài)時執(zhí)行的代碼 }public override void Execute(Main Entity){//這里添加持續(xù)此狀態(tài)刷新代碼//當滿足某條件后 我們可以繼續(xù)進行狀態(tài)切換 執(zhí)行如下代碼 切換到 Over狀態(tài) Entity.GetFSM().ChangeState(MainState_Over.Instance()); }public override void Exit(Main Entity){//這里添加離開此狀態(tài)時執(zhí)行代碼 } }/*** Over狀態(tài)*/ public class MainState_Over : State[Main> {public static MainState_Over instance;/*構造函數(shù)單例化*/public static MainState_Over Instance(){if (instance == null)instance = new MainState_Over();return instance;}public override void Enter(Main Entity){//這里添加進入此狀態(tài)時執(zhí)行的代碼 }public override void Execute(Main Entity){//這里添加持續(xù)此狀態(tài)刷新代碼//如之前兩個狀態(tài)類一樣 同理 當滿足一定狀態(tài)后 可以切換回Ready狀態(tài) Entity.GetFSM().ChangeState(MainState_Ready.Instance()); }public override void Exit(Main Entity){//這里添加離開此狀態(tài)時執(zhí)行代碼 } }

代碼有點長,主要是為了讓大家能夠看清楚如何進行一個狀態(tài)的編寫,其實基類都是一樣的,都是重復內(nèi)容。 這里我們看到,除了定義一個全局的狀態(tài)類之外,我們還添加了Ready、Run、Over三個狀態(tài)。重點注意一下Execute函數(shù),這里是狀態(tài)切換的關鍵,當帶此狀態(tài)綁定的對象Update時就在不停的執(zhí)行Execute里的代碼段,當滿足一定條件后,即達成狀態(tài)的切換。

這里我們看一下之前的狀態(tài)機代碼里的ChangeState方法,就知道整個狀態(tài)切換是如何工作的了:

/*狀態(tài)改變*/public void ChangeState (State[entity_type> pNewState){if (pNewState == null) {Debug.LogError ("can't find this state");}//觸發(fā)退出狀態(tài)調(diào)用Exit方法 m_pCurrentState.Exit(m_pOwner);//保存上一個狀態(tài) m_pPreviousState = m_pCurrentState;//設置新狀態(tài)為當前狀態(tài)m_pCurrentState = pNewState;m_pCurrentState.Target = m_pOwner;//進入當前狀態(tài)調(diào)用Enter方法 m_pCurrentState.Enter (m_pOwner);}

可以看到當狀態(tài)切換時,會自動觸發(fā)當前狀態(tài)的Exit方法和目標狀態(tài)的Enter方法。這樣就完成了一整個狀態(tài)的切換過程。

到這里整個有限狀態(tài)機體系基本就算完工了,剩下的是如何在Main里進行MainState類的創(chuàng)建及使用,Main.cs代碼如下:

using UnityEngine; using System.Collections;public class Main : MonoBehaviour{StateMachine[Main> m_pStateMachine;//定義一個狀態(tài)機void Start () {m_pStateMachine = new StateMachine[Main>(this);//初始化狀態(tài)機m_pStateMachine.SetCurrentState(MainState_Ready.Instance()); //設置一個當前狀態(tài)m_pStateMachine.SetGlobalStateState(MainState.Instance());//設置全局狀態(tài) }void Update (){ m_pStateMachine.SMUpdate();}/*返回狀態(tài)機*/public StateMachine[Main> GetFSM (){return m_pStateMachine;}}

寫到這里我們整個狀態(tài)機的框架及使用流程就基本結束了,這里要注意幾個問題: ①不要在SetCurrentState()方法調(diào)用前,調(diào)用ChangeState()方法,否則會出現(xiàn)null對象錯誤,具體原因很簡單,看一下ChangeState()里的代碼調(diào)用了哪些變量就知道了。 ②狀態(tài)間的通信,這個狀態(tài)機其實還是有未完善的地方的,目前狀態(tài)間的通知是通過直接調(diào)用其他狀態(tài)機的ChangeState()方法實現(xiàn)的,這樣勢必要先獲取該對象的腳本,這個功能待完善吧。 ③在U3D里每個游戲對象初始化并調(diào)用Start()方法的時機是不一樣的,所以要注意,開始游戲時不要直接進入開始狀態(tài),而是要有一個等待態(tài)來讓所有的游戲對象完成Start()方法后再調(diào)用這些對象的狀態(tài)機。

另外,多個狀態(tài)機間的通信,就像上文②中所述那樣,僅僅是通過調(diào)用ChangeState()方法來實現(xiàn),并不是非常完善,所以暫時不做講解,以免誤導大家,待日后有較好解決方案再另行開篇。 此FSM狀態(tài)機僅為一個雛形,還有很多功能及優(yōu)化要做,但對于入門FSM有限狀態(tài)機來說,已經(jīng)實現(xiàn)了其最主要的功能。不足之處歡迎大家提出討論,并幫助加以完善。

謝謝關注。

轉載于:https://www.cnblogs.com/softimagewht/p/4042431.html

總結

以上是生活随笔為你收集整理的U3D-FSM有限状态机的简单设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。