Unity學(xué)習(xí)之FSM有限狀態(tài)機(jī)
前言:一個游戲里的一個人物會存在多種狀態(tài),那么就需要有一個專門管理這些狀態(tài)的類。不然會顯得雜亂無章,不易于后面狀態(tài)的增加或者減少。
思路:既然要方便管理,那么首先肯定得有個系統(tǒng)類(專門用來存放所有的狀態(tài)、狀態(tài)的增刪等功能);然后就是需要把所有的狀態(tài)都單獨寫一個類(已達(dá)到修改某個狀態(tài)的時候,其他狀態(tài)不會受到影響)。
狀態(tài)管理類:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FSMSystem { private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>(); private StateID currentStateID; private FSMState currentFSMState; public void Update(GameObject npc) { currentFSMState.Act(npc); currentFSMState.Reason(npc); } /// <summary> /// 添加狀態(tài) /// </summary> /// <param name="fSMState"></param> public void AddState(FSMState fSMState) { if (fSMState == null) return; //if (currentFSMState == null) //{ currentStateID = fSMState.ID; currentFSMState = fSMState; //} if (states.ContainsKey(currentStateID)) return; states.Add(currentStateID, currentFSMState); } /// <summary> /// 刪除狀態(tài) /// </summary> /// <param name="stateID"></param> public void DeleteState(StateID stateID) { if (stateID == StateID.Null) return; if (!states.ContainsKey(stateID)) return; states.Remove(stateID); } /// <summary> /// 執(zhí)行狀態(tài)條件轉(zhuǎn)換 /// </summary> /// <param name="transition"></param> public void PerformTransition(Transition transition) { if (transition == Transition.NullTransition) return; StateID stateID = currentFSMState.GetStateID(transition); if (stateID == StateID.Null) return; if (!states.ContainsKey(stateID)) return; FSMState fSMState = states[stateID]; currentFSMState.StateExit(); currentFSMState = fSMState; currentStateID = fSMState.ID; currentFSMState.StateEnter(); } }
狀態(tài)基類:
using System.Collections; using System.Collections.Generic; using UnityEngine; public enum Transition { NullTransition, SeePlayer,//發(fā)現(xiàn)玩家 LostPlayer,//玩家脫離視野范圍 AttackPlayer,//攻擊玩家 } public enum StateID { Null, Chase,//追逐 Patrol,//巡邏 Attack,//攻擊 } public abstract class FSMState { protected Transition transition; protected StateID stateID; protected FSMSystem fSM; public StateID ID { get { return stateID; } } protected Dictionary<Transition, StateID> dic = new Dictionary<Transition, StateID>(); public FSMState(FSMSystem fSM) { this.fSM = fSM; } /// <summary> /// 增加狀態(tài) /// </summary> /// <param name="transition"></param> /// <param name="stateID"></param> public void AddTransition(Transition transition, StateID stateID) { if (transition == Transition.NullTransition) return; if (stateID == StateID.Null) return; if (dic.ContainsKey(transition)) return; dic.Add(transition, stateID); } /// <summary> /// 刪除狀態(tài) /// </summary> /// <param name="transition"></param> public void DeleteTransition(Transition transition) { if (transition == Transition.NullTransition) return; if (!dic.ContainsKey(transition)) return; dic.Remove(transition); } /// <summary> /// 獲取狀態(tài) /// </summary> /// <param name="transition"></param> /// <returns></returns> public StateID GetStateID(Transition transition) { if (transition == Transition.NullTransition) return StateID.Null; if (!dic.ContainsKey(transition)) return StateID.Null; return dic[transition]; } /// <summary> /// 進(jìn)入狀態(tài) /// </summary> public virtual void StateEnter() { } /// <summary> /// 退出狀態(tài) /// </summary> public virtual void StateExit() { } /// <summary> /// 狀態(tài)持續(xù)中,,, /// </summary> /// <param name="npc"></param> public abstract void Act(GameObject npc); /// <summary> /// 狀態(tài)退出前,,, /// </summary> /// <param name="npc"></param> public abstract void Reason(GameObject npc); }
巡邏狀態(tài):
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 巡邏狀態(tài) /// </summary> public class PatrolState : FSMState { /// <summary> /// 巡邏路徑點集合 /// </summary> private Transform[] paths; /// <summary> /// 當(dāng)前巡邏路徑點索引 /// </summary> private int index = 0; /// <summary> /// 移動速度 /// </summary> private float moveSpeed = 0.5f; /// <summary> /// 玩家 /// </summary> private Transform player; public PatrolState(FSMSystem fSM, Transform player) : base(fSM) { this.player = player; paths = GameObject.Find("Path").GetComponentsInChildren<Transform>(); stateID = StateID.Patrol; } public override void Act(GameObject npc) { npc.transform.LookAt(paths[index].position); npc.transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed); if (Vector3.Distance(npc.transform.position, paths[index].position) < 1) { index++; index %= paths.Length; } } public override void Reason(GameObject npc) { npc.GetComponent<Animator>().SetFloat("Speed", moveSpeed ); if (Vector3.Distance(player.position, npc.transform.position) < 10) { fSM.PerformTransition(Transition.SeePlayer); } } }
追逐狀態(tài):
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 追逐狀態(tài) /// </summary> public class ChaseState : FSMState { /// <summary> /// 移動速度 /// </summary> private float moveSpeed = 2f; /// <summary> /// 玩家 /// </summary> private Transform player; public ChaseState(FSMSystem fSM, Transform player) : base(fSM) { stateID = StateID.Chase; this. player = player; } public override void Act(GameObject npc) { npc.transform.LookAt(player.position); npc.transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed); } public override void Reason(GameObject npc) { npc.GetComponent<Animator>().SetFloat("Speed", moveSpeed / 2); if (Vector3.Distance(player.position, npc.transform.position) >= 10) { fSM.PerformTransition(Transition.LostPlayer); } else if (Vector3.Distance(player.position, npc.transform.position) <= 1f ) { fSM.PerformTransition(Transition.AttackPlayer); } } }
攻擊狀態(tài):
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 攻擊狀態(tài) /// </summary> public class AttackState : FSMState { /// <summary> /// 玩家 /// </summary> private Transform player; public AttackState(FSMSystem fSM, Transform player) : base(fSM) { stateID = StateID.Attack; this.player = player; } public override void Act(GameObject npc) { } public override void Reason(GameObject npc) { if (Vector3.Distance(player.position, npc.transform.position) > 1f) { if (Vector3.Distance(player.position, npc.transform.position) >= 10) { fSM.PerformTransition(Transition.LostPlayer); } else if (Vector3.Distance(player.position, npc.transform.position) < 10) { fSM.PerformTransition(Transition.SeePlayer); } return; } npc.GetComponent<Animator>().SetTrigger("Attack01"); } }
狀態(tài)持有者實現(xiàn)類:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { private FSMSystem fSM; private Transform player; private void Start() { fSM = new FSMSystem(); FSMState patrolState = new PatrolState(fSM, player); patrolState.AddTransition(Transition.SeePlayer, StateID.Chase); patrolState.AddTransition(Transition.AttackPlayer, StateID.Attack); //patrolState.AddTransition(Transition.LostPlayer, StateID.Patrol); FSMState chaseState = new ChaseState(fSM, player); chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol); chaseState.AddTransition(Transition.AttackPlayer, StateID.Attack); //chaseState.AddTransition(Transition.SeePlayer, StateID.Chase); FSMState attackState = new AttackState(fSM, player); attackState.AddTransition(Transition.SeePlayer, StateID.Chase); attackState.AddTransition(Transition.LostPlayer, StateID.Patrol); //attackState.AddTransition(Transition.AttackPlayer, StateID.Attack); fSM.AddState(patrolState); fSM.AddState(chaseState); fSM.AddState(attackState); } private void Update() { fSM.Update(gameObject); } }
到此這篇關(guān)于Unity學(xué)習(xí)之FSM有限狀態(tài)機(jī)的文章就介紹到這了,更多相關(guān)UnityFSM有限狀態(tài)機(jī)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C#中三個關(guān)鍵字params,Ref,out
本文主要討論params關(guān)鍵字,ref關(guān)鍵字,out關(guān)鍵字。非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-05-05c# winform treelistview的使用(treegridview)實例詳解
這篇文章主要介紹了c# winform treelistview的使用(treegridview),本文通過實例代碼給大家詳細(xì)介紹,需要的朋友可以參考下2017-12-12c#使用FreeSql生產(chǎn)環(huán)境時自動升級備份數(shù)據(jù)庫
使用FreeSql,包含所有的ORM數(shù)據(jù)庫,都會存在這樣的問題。在codefirst模式下,根據(jù)代碼自動更新數(shù)據(jù)庫,都建議不要在生產(chǎn)環(huán)境使用。因為容易丟失數(shù)據(jù),本文提供一種自動更新數(shù)據(jù)庫的解決的思路:在判斷需要升級時,才自動升級,同時升級前先備份數(shù)據(jù)庫2021-06-06C#實現(xiàn)炫酷啟動圖-動態(tài)進(jìn)度條效果
這篇文章主要介紹了基于C#實現(xiàn)炫酷啟動圖-動態(tài)進(jìn)度條 效果,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05