AI-有限狀態機(追擊,巡邏)

  • 有限狀態機的基類,包含各種狀態
  • using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    
    public enum Transition
    {
        NullTransition=0,
        SeePlayer,
        LostPlayer
    }
    
    
    public enum StateID
    {
        NullStateID=0,
        Patrol,
        Chase
    }
    
    public abstract class FSMState
    {
        protected StateID stateID;
        public StateID ID { get { return stateID; } }
        protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
        protected FSMSystem fsm;
    
        public FSMState(FSMSystem fsm)
        {
            this.fsm = fsm;
        }
    
        public void AddTransition(Transition transition,StateID id)
        {
            if (transition==Transition.NullTransition)
            {
                Debug.LogError("不允許NullTransition");return;
            }
            if (id==StateID.NullStateID)
            {
                Debug.LogError("不允許NullStateID");return;
            }
            if (map.ContainsKey(transition))                // 判斷key是否存在
            {
                Debug.LogError("添加轉換條件的時候" + transition + "已經存在於map中");return;
            }
            map.Add(transition, id);
        }
    
        public void DeleteTransition(Transition transition)
        {
            if (transition == Transition.NullTransition)
            {
                Debug.LogError("不允許NullTransition"); return;
            }
            if (map.ContainsKey(transition)==false)                // 判斷key是否存在
            {
                Debug.LogError("刪除轉換條件的時候" + transition + "不存在於map中"); return;
            }
            map.Remove(transition);
        }
    
        public StateID GetOutputState (Transition transition)
        {
            if (map.ContainsKey(transition))
            {
                return map[transition];
            }
            return StateID.NullStateID;
        }
    
        //進入狀態之前的虛函數
        public virtual void DoBeforEntering() { }
        //離開狀態,狀態發生轉換
        public virtual void DoAfterLeaving() { }
        //抽象方法必須重寫
        public abstract void Act(GameObject gameObject);
        //判斷轉換條件
        public abstract void Reason(GameObject gameObject);
    }
    
  • 控制狀態之間的轉換
  • 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 currentState;
    
        public void AddState(FSMState s)
        {
            if (s==null)
            {
                Debug.LogError("FSMState不能爲空");return;
            }
                //默認狀態
            if (currentState==null)
            {
                currentState = s;
                currentStateID = s.ID;
            }
            //添加到字典裏
            if (states.ContainsKey(s.ID))
            {
                Debug.LogError("狀態" + s.ID + "已經存在");return;
            }
            states.Add(s.ID, s);
        }
    
        public void DeleteState(StateID id)
        {
            if (id==StateID.NullStateID)
            {
                Debug.LogError("無法刪除空狀態");return;
            }
            if (states.ContainsKey(id)==false)
            {
                Debug.LogError("無法刪除不存在的:" + id);return;
            }
            states.Remove(id);
        }
    
        //根據條件進行狀態切換
        public void PerformTransition(Transition transition)
        {
            if (transition ==Transition.NullTransition)
            {
                Debug.LogError("無法執行空的轉換條件");return;
            }
            StateID id = currentState.GetOutputState(transition);
    
            if (id==StateID.NullStateID)
            {
                Debug.LogWarning("當前狀態" + currentStateID + "無法根據轉換條件" + transition + "發生轉換");return;
            }
            FSMState fSMState = states[id];
    
            currentState.DoAfterLeaving();          //舊狀態離開
            currentState = fSMState;
            currentStateID = id;
            currentState.DoBeforEntering();         //新狀態進入
        }
    
        //調用Act方法
        public void Update(GameObject gameObject)
        {
            currentState.Act(gameObject);
            currentState.Reason(gameObject);
        }
    
    }
    
  • 敵人類
  • using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Enemy : MonoBehaviour {
    
        private FSMSystem fsm;
    	
    	void Start () {
            InitFSM();
    	}
    	
    	//對有限狀態機進行初始化
        private void InitFSM()
        {
            fsm = new FSMSystem();
            FSMState patrolState = new PatrolState(fsm);
            //轉換條件
            patrolState.AddTransition(Transition.SeePlayer,StateID.Chase);
    
            FSMState chaseState = new ChaseState(fsm);
            chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol);
    
            fsm.AddState(patrolState);
            fsm.AddState(chaseState);
        }
    
    	void Update () {
            fsm.Update(this.gameObject);
    	}
    }
    
  • 巡邏狀態和追擊狀態
  • using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PatrolState : FSMState
    {
        //路徑點
        private List<Transform> path = new List<Transform>();
        private int index = 0;      //移動的開始索引
        private Transform playerTransform;
    
        public PatrolState(FSMSystem fsm) : base(fsm)
        {
            stateID = StateID.Patrol;
    
            //在這裏獲取一次,節省性能
            Transform pathTran = GameObject.Find("Path").transform;
            Transform[] children = pathTran.GetComponentsInChildren<Transform>();   //還包含父物體
            //剔除父物體
            foreach (Transform child in children)
            {
                if (child!= pathTran)
                {
                    path.Add(child);
                }
            }
    
            playerTransform = GameObject.Find("Player").transform;
    
        }
    
        //這個方法在FSMSystem中調用
        public override void Act(GameObject gameObject)
        {
            gameObject.transform.LookAt(path[index].position);
            gameObject.transform.Translate(Vector3.forward * Time.deltaTime * 3);
            if (Vector3.Distance(gameObject.transform.position,path[index].position)<1)     //自身位置與目標位置的距離
            {
                index++;
                index %= path.Count;    //index在數組內循環
            }
        }
    
        public override void Reason(GameObject gameObject)
        {
            //與主角距離小於3的時候開始追擊玩家
            if (Vector3.Distance(playerTransform.position,gameObject.transform.position)<3)
            {
                fsm.PerformTransition(Transition.SeePlayer);
            } 
        }
    }
    
  • using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class ChaseState : FSMState
    {
        private Transform playerTransform;
    
        public ChaseState(FSMSystem fsm) : base(fsm)
        {
            stateID = StateID.Chase;
            playerTransform = GameObject.Find("Player").transform;
        }
    
        public override void Act(GameObject gameObject)
        {
            gameObject.transform.LookAt(playerTransform.position);
            gameObject.transform.Translate(Vector3.forward * 2 * Time.deltaTime);
        }
    
        public override void Reason(GameObject gameObject)
        {
            //與主角距離大於6時,執行尋路狀態
            if (Vector3.Distance(playerTransform.position, gameObject.transform.position) > 6)
            {
                fsm.PerformTransition(Transition.LostPlayer);
            }
        }
    }
    
  •  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章