在之前有过介绍一个可视化有限状态机编辑器插件PlayerMaker

在这里也可以在我们的代码中实现一个状态机

本文源码地址:点击打开链接

首先创建一个脚本,来管理我们的各个状态

 

   using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Linq;
     
    /// <summary>
    /// 状态ID
    /// </summary>
    public enum FSMStateID
    {
        NullFSMStateID,
        PatrolFSMStateID,//巡逻状态
        ChaseFSMStateID,//追逐状态
    }
     
     
    /// <summary>
    /// 状态转化条件
    /// </summary>
    public enum FSMTransition
    {
        SeePlayer,//看到主角(目标)
        LeavePlayer,//远离敌人(目标)
    }
     
    public class FSMSystem
    {
        private FSMStateID mCurrentStateID;
        private FSMBaseState mCurrentState;
     
        private Dictionary<FSMStateID, FSMBaseState> mFSMStateDic = new Dictionary<FSMStateID, FSMBaseState>();
     
     
        public void AddFSMSate(FSMBaseState state)
        {
            if (state == null)
            {
                Debug.Log("角色状态为空,无法添加");
                return;
            }
            if (mCurrentState == null)
            {
                //第一个添加的状态被作为系统首个运行的状态
                mCurrentStateID = state.mStateID;
                mCurrentState = state;
                mCurrentState.StateStart();
            }
            if (mFSMStateDic.ContainsValue(state))
            {
                Debug.Log("容器内存在该状态");
                return;
            }
            mFSMStateDic.Add(state.mStateID, state);
        }
     
        public void DeleteFSMSate(FSMBaseState state)
        {
            if (state == null)
            {
                Debug.Log("角色状态为空,无法添加");
                return;
            }
            if (!mFSMStateDic.ContainsValue(state))
            {
                Debug.Log("容器内不存在该状态");
                return;
            }
            mFSMStateDic.Remove(state.mStateID);
        }
     
        //更新(执行)系统
        public void UpdateSystem()
        {
            if (mCurrentState != null)
            {
                mCurrentState.StateUpdate();
                mCurrentState.TransitionReason();
            }
        }
     
        //转换状态
        public void TransitionFSMState(FSMTransition transition)
        {
            FSMStateID stateID = mCurrentState.GetStateIdByTransition(transition);
            if (stateID != FSMStateID.NullFSMStateID)
            {
                mCurrentStateID = stateID;
                mCurrentState.StateEnd();
                //换状态
                mCurrentState = mFSMStateDic.FirstOrDefault(q => q.Key == stateID).Value;
                mCurrentState.StateStart();
            }
        }
    }

 


各个状态(巡逻状态、追逐状态)抽象理解为一个对象

创建一个状态基类,各个状态子类中可以继承重写这个基类方法 

   using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Linq;
     
    public abstract class FSMBaseState
    {
        public FSMStateID mStateID { get; set; }    //状态ID
        public FSMSystem mFSMSystem { get; set; }   //该对象属于在哪个状态机
     
        public Dictionary<FSMTransition, FSMStateID> mFSMStateIdDic = new Dictionary<FSMTransition, FSMStateID>();
     
        public FSMBaseState(FSMSystem fsmSystem, FSMStateID stateID)
        {
            this.mFSMSystem = fsmSystem;
            this.mStateID = stateID;
        }
     
        public void AddTransition(FSMTransition transition, FSMStateID stateID)
        {
            if (mFSMStateIdDic.ContainsKey(transition))
            {
                Debug.Log("本状态已经包含了该转换条件");
                return;
            }
            mFSMStateIdDic.Add(transition, stateID);
        }
     
        public void DeleteTransition(FSMTransition transition)
        {
            if (!mFSMStateIdDic.ContainsKey(transition))
            {
                Debug.Log("容器中没有该转换条件");
                return;
            }
            mFSMStateIdDic.Remove(transition);
        }
     
        public FSMStateID GetStateIdByTransition(FSMTransition transition)
        {
            if (!mFSMStateIdDic.ContainsKey(transition))
            {
                Debug.Log("容器内没有该转换条件,无法获取状态");
                return FSMStateID.NullFSMStateID;
            }
     
            return mFSMStateIdDic.FirstOrDefault(q => q.Key == transition).Value;
        }
     
        public abstract void StateStart();
        public abstract void StateUpdate();
        public abstract void StateEnd();
        //转化状态条件
        public abstract void TransitionReason();
    }

以下是巡逻状态
  

  using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class FSMPatrolState : FSMBaseState
    {
        //路径点
        private List<Transform> mStargetPointTransform = new List<Transform>();
        //路径点索引
        private int mPointIndex = 0;
        //士兵
        private GameObject mSliderObj { get; set; }
        //主角
        private GameObject mPlayerObj { get; set; }
        //士兵移动速度
        private float mMoveSpeed = 4f;
     
        public FSMPatrolState(FSMSystem fsmSystem) : base(fsmSystem, FSMStateID.PatrolFSMStateID) { }
     
        public override void StateStart()
        {
            //获取路径点
            Transform[] transforms = GameObject.Find("Points").GetComponentsInChildren<Transform>();
            foreach (var m_transform in transforms)
            {
                if (m_transform != GameObject.Find("Points").transform)
                {
                    mStargetPointTransform.Add(m_transform);
                    Debug.Log(m_transform.position);
                }
            }
     
            //获取士兵对象
            mSliderObj = GameObject.Find("Slider");
            //获取主角对象
            mPlayerObj = GameObject.Find("Player");
        }
     
        public override void StateUpdate()
        {
            //确实目标点并移动  
            mSliderObj.transform.LookAt(this.mStargetPointTransform[this.mPointIndex].position);
            mSliderObj.transform.Translate(Vector3.forward * Time.deltaTime * mMoveSpeed);
     
            if (Vector3.Distance(mSliderObj.transform.position, this.mStargetPointTransform[this.mPointIndex].position) < 0.5f)
            {
                //切换目标点
                this.mPointIndex++;
                if (this.mPointIndex >= this.mStargetPointTransform.Count)
                {
                    this.mPointIndex = 0;
                }    
            }
        }
     
        public override void StateEnd()
        {
            
        }
     
        public override void TransitionReason()
        {
            if (Vector3.Distance(mSliderObj.transform.position, mPlayerObj.transform.position) <= 2.0f)
            {
                //转化状态
                if (this.mFSMSystem == null)
                {
                    Debug.Log("目标状态机为空");
                    return;
                }
                mFSMSystem.TransitionFSMState(FSMTransition.SeePlayer);
            }
        }
    }

以下是追逐状态

 

   using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class FSMChaseState : FSMBaseState
    {
        private GameObject mPlayerObj { get; set; }
        private GameObject mSliderObj { get; set; }
        private float mSliderMoveSpeed = 6.0f;
     
        public FSMChaseState(FSMSystem fsmSystem) : base(fsmSystem, FSMStateID.ChaseFSMStateID) { }
     
        public override void StateStart()
        {
            mPlayerObj = GameObject.Find("Player");
            mSliderObj = GameObject.Find("Slider");
        }
     
        public override void StateUpdate()
        {
            if (Vector3.Distance(mPlayerObj.transform.position, mSliderObj.transform.position) <= 10.0f)
            {
                //开始面向主角
                mSliderObj.transform.LookAt(mPlayerObj.transform.position);
                //开始追逐
                mSliderObj.transform.Translate(Vector3.forward * Time.deltaTime * mSliderMoveSpeed);
            }
        }
     
        public override void StateEnd()
        {
            
        }
     
        public override void TransitionReason()
        {
            //当主角远离敌人
            if (Vector3.Distance(mPlayerObj.transform.position, mSliderObj.transform.position) > 10.0f)
            {
                //转化状态
                if (this.mFSMSystem == null)
                {
                    Debug.Log("目标状态机为空");
                    return;
                }
                mFSMSystem.TransitionFSMState(FSMTransition.LeavePlayer);
            }
        }
    }


该状态机的优点在于当有不同类型的状态时候,可以直接添加到状态系统内,而不要需要状态系统内部的运行逻辑
   

 using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class Slider : MonoBehaviour
    {
        private FSMSystem fsmSystem { get; set; }
     
        void Start ()
        {
            fsmSystem = new FSMSystem();
     
            //巡逻状态,在构造参数传一个系统参数,确定该状态是在哪个状态系统中管理的,状态转换的时候调用
            FSMBaseState patrolState = new FSMPatrolState(fsmSystem);
            patrolState.AddTransition(FSMTransition.SeePlayer, FSMStateID.ChaseFSMStateID);//巡逻状态转化条件
     
            //追逐状态
            FSMBaseState chaseState = new FSMChaseState(fsmSystem);
            chaseState.AddTransition(FSMTransition.LeavePlayer, FSMStateID.PatrolFSMStateID);
            
            fsmSystem.AddFSMSate(patrolState);
            fsmSystem.AddFSMSate(chaseState);
        }
        
        void Update ()
        {
            fsmSystem.UpdateSystem();    
        }

}