精华内容
下载资源
问答
  • 基于unityFSM

    2018-03-23 13:24:23
    一个基于unity设计的FSM状态机代码库, 一个基于unity设计的FSM状态机代码库
  • Unity FSM(有限状态机)

    千次阅读 2020-04-14 01:12:47
    先看下效果: FSM ,有限状态机,一个可以枚举出有限个状态,...Unity中的Animator就是一个FSM了,不过Animator是控制角色动画播放的,什么状态的时候播放什么动画。而这里写的FSM是控制角色AI的,什么状态就做什么...

    先看下效果:
    在这里插入图片描述

    FSM ,有限状态机,一个可以枚举出有限个状态,并且这些状态在特定条件下是能够来回切换的。

    在游戏中经常看到的一些AI,如敌人巡逻,巡逻过程中看到玩家就追击,追上了就攻击,追不上并且有了一定的距离就返回去继续巡逻。

    Unity中的Animator就是一个FSM了,不过Animator是控制角色动画播放的,什么状态的时候播放什么动画。而这里写的FSM是控制角色AI的,什么状态就做什么事。

    FSM 跟 Switch case做的事一样一样,类比于 Switch 就是将case中的逻辑封装到各个State中了。
    为什么要这样做呢?为了方便扩展,如果后期需要加入新状态,只需要继承基类,添加实现就好,不用修改原来的代码,对外界开放扩展,这就是开闭原则(对修改关闭,对扩展开放)。

    实现过程

    先来个FSMState状态类:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 转换条件
    /// </summary>
    public enum Transition
    {
        NullTransition=0,//空的转换条件
        SeePlayer,//看到玩家
        LostPlayer,//追赶过程中遗失目标玩家
    }
    
    /// <summary>
    /// 当前状态
    /// </summary>
    public enum StateID
    {
        NullState,//空的状态
        Patrol,//巡逻状态
        Chase,//追赶状态
    }
    
    public abstract class FSMState
    {
        protected StateID stateID;
        public StateID StateID { get { return stateID; } }
        protected Dictionary<Transition, StateID> transitionStateDic = new Dictionary<Transition, StateID>();
        protected FSMSystem fSMSystem;
    
        public FSMState(FSMSystem fSMSystem)
        {
            this.fSMSystem = fSMSystem;
        }
    
        /// <summary>
        /// 添加转换条件
        /// </summary>
        /// <param name="trans">转换条件</param>
        /// <param name="id">转换条件满足时执行的状态</param>
        public void AddTransition(Transition trans,StateID id)
        {
            if(trans==Transition.NullTransition)
            {
                Debug.LogError("不允许NullTransition");
                return;
            }
            if(id==StateID.NullState)
            {
                Debug.LogError("不允许NullStateID");
                return;
            }
            if(transitionStateDic.ContainsKey(trans))
            {
                Debug.LogError("添加转换条件的时候" + trans + "已经存在于transitionStateDic中");
                return;
            }
            transitionStateDic.Add(trans, id);
        }
        /// <summary>
        /// 删除转换条件
        /// </summary>
        public void DeleteTransition(Transition trans)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError("不允许NullTransition");
                return;
            }
            if(!transitionStateDic.ContainsKey(trans))
            {
                Debug.LogError("删除转换条件的时候" + trans + "不存在于transitionStateDic中");
                return;
            }
            transitionStateDic.Remove(trans);
        }
    
        /// <summary>
        /// 获取当前转换条件下的状态
        /// </summary>
        public StateID GetOutputState(Transition trans)
        {
            if(transitionStateDic.ContainsKey(trans))
            {
                return transitionStateDic[trans];
            }
            return StateID.NullState;
        }
        /// <summary>
        /// 进入新状态之前做的事
        /// </summary>
        public virtual void DoBeforeEnter() { }
        /// <summary>
        /// 离开当前状态时做的事
        /// </summary>
        public virtual void DoAfterLeave() { }
        /// <summary>
        /// 当前状态所做的事
        /// </summary>
        public abstract void Act(GameObject npc);
        /// <summary>
        /// 在某一状态执行过程中,新的转换条件满足时做的事
        /// </summary>
        public abstract void Reason(GameObject npc);//判断转换条件
    }
    
    

    再来个FSMSystem,来管理所有的状态:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class FSMSystem
    {
        private Dictionary<StateID, FSMState> stateDic = new Dictionary<StateID, FSMState>();
        private StateID currentStateID;
        private FSMState currentState;
    
        /// <summary>
        /// 更新npc的动作
        /// </summary>
        public void Update(GameObject npc)
        {
            currentState.Act(npc);
            currentState.Reason(npc);
        }
    
        /// <summary>
        /// 添加新状态
        /// </summary>
        public void AddState(FSMState state)
        {
            if(state==null)
            {
                Debug.LogError("FSMState不能为空");
                return;
            }
            if(currentState==null)
            {
                currentState = state;
                currentStateID = state.StateID;
            }
            if(stateDic.ContainsKey(state.StateID))
            {
                Debug.LogError("状态" + state.StateID + "已经存在,无法重复添加");
                return;
            }
            stateDic.Add(state.StateID, state);
        }
    
        /// <summary>
        /// 删除状态
        /// </summary>
        public void DeleteState(StateID stateID)
        {
            if(stateID==StateID.NullState)
            {
                Debug.LogError("无法删除空状态");
                return;
            }
            if(!stateDic.ContainsKey(stateID))
            {
                Debug.LogError("无法删除不存在的状态");
                return;
            }
            stateDic.Remove(stateID);
        }
    
        /// <summary>
        /// 执行过渡条件满足时对应状态该做的事
        /// </summary>
        public void PerformTransition(Transition transition)
        {
            if(transition==Transition.NullTransition)
            {
                Debug.LogError("无法执行空的转换条件");
                return;
            }
            StateID id = currentState.GetOutputState(transition);
            if(id==StateID.NullState)
            {
                Debug.LogWarning("当前状态" + currentStateID + "无法根据转换条件" + transition + "发生转换");
                return;
            }
            if(!stateDic.ContainsKey(id))
            {
                Debug.LogError("在状态机里面不存在状态" + id + ",无法进行状态转换");
                return;
            }
            FSMState state = stateDic[id];
            currentState.DoAfterLeave();
            currentState = state;
            currentStateID = state.StateID;
            currentState.DoBeforeEnter();
        }
    }
    
    

    以上就是FSM重要的类,接下来就是使用FSM了。

    先新建一个PatrolState巡逻状态:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 巡逻状态
    /// </summary>
    public class PatrolState : FSMState
    {
        private List<Transform> pathList = new List<Transform>();
        private int index = 0;
        private Transform playerTrans;
        public PatrolState(FSMSystem fSMSystem) : base(fSMSystem)
        {
            stateID = StateID.Patrol;
            Transform pathTrans = GameObject.Find("path").transform;
            Transform[] trans = pathTrans.GetComponentsInChildren<Transform>();
            foreach (Transform t in trans)
            {
                if(t!= pathTrans)
                {
                    pathList.Add(t);
                }
            }
            playerTrans = GameObject.Find("Player").transform;
        }
    
        /// <summary>
        /// 当前状态所做的事,巡逻
        /// </summary>
        public override void Act(GameObject npc)
        {
            npc.transform.LookAt(pathList[index]);
            npc.transform.Translate(Vector3.forward * Time.deltaTime * 3);
            if(Vector3.Distance(npc.transform.position,pathList[index].position)<0.5f)
            {
                index++;
                index %= pathList.Count;
            }
        }
    
        /// <summary>
        /// 在某一状态执行过程中,新的转换条件满足时做的事,追赶
        /// </summary>
        public override void Reason(GameObject npc)
        {
            if(Vector3.Distance(playerTrans.position,npc.transform.position)<3)
            {
                fSMSystem.PerformTransition(Transition.SeePlayer);
            }
        }
    }
    
    

    再来个ChaseState追赶类:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 追赶状态
    /// </summary>
    public class ChaseState : FSMState
    {
        private Transform playerTrans;
        public ChaseState(FSMSystem fSMSystem) : base(fSMSystem)
        {
            stateID = StateID.Chase;
            playerTrans = GameObject.Find("Player").transform;
        }
    
        /// <summary>
        /// 当前状态所做的事,追赶
        /// </summary>
        public override void Act(GameObject npc)
        {
            npc.transform.LookAt(playerTrans);
            npc.transform.Translate(Vector3.forward * Time.deltaTime * 2);
        }
    
        /// <summary>
        /// 在某一状态执行过程中,新的转换条件满足时做的事,继续巡逻
        /// </summary>
        public override void Reason(GameObject npc)
        {
            if(Vector3.Distance(playerTrans.position, npc.transform.position) > 6)
            {
                fSMSystem.PerformTransition(Transition.LostPlayer);
            }
        }
    }
    
    

    最后我们新建一个敌人的脚本,需要挂载在敌人身上:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 敌人的类,需要挂载在敌人身上
    /// </summary>
    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(gameObject);
        }
    }
    
    

    路径放在path下,Enemy.cs挂载在敌人身上。名为Player的玩家一靠近就会追赶了,追不上就返回继续巡逻了。

    展开全文
  • 如果在此状态下触发转换,则FSM应该处于哪个状态是当前状态。 方法Reason用于确定触发的条件 方法Act具有执行角色在此状态下应执行的操作的代码。 using System.Collections; using System.Collections...

    角色的有限状态 :

     

    此类表示有限状态系统中的状态。
    每个状态都有一个字典,其中有成对的(transition-stateID)显示
    如果在此状态下触发转换,则FSM应该处于哪个状态是当前状态。
    方法Reason用于确定触发的条件
    方法Act具有执行角色在此状态下应执行的操作的代码。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //状态转换条件
    public enum CubeTransition
    {
        NullTansition,
        SeeEnemy,
        NoEnemy,
        CanAttack
    }
    
    //状态的ID
    public enum CubeStateID 
    {
        NullState,
        Idle,
        Chase,
        Attack
    }
    /// <summary>
    /// 此类表示有限状态系统中的状态。
    /// </summary>
    public abstract class ICubeState  {
    
        protected Dictionary<CubeTransition, CubeStateID> mMap = new Dictionary<CubeTransition, CubeStateID>();
        protected CubeStateID mStateID;
        protected CubeFSMSystem mFSM;
        public CubePlayer mPlayer;
    
        public CubeStateID StateID { get { return mStateID; } }
    
        public ICubeState(CubeFSMSystem fsm,CubePlayer player)
        {
            mFSM = fsm;
            mPlayer = player;
        }
    
        public void AddTransition( CubeTransition trans,CubeStateID id)
        {
            if (trans == CubeTransition.NullTansition)
            {
                Debug.LogWarning("当前状态CubeTransiton为空 :"+trans);
                return;
            }
    
            if (id == CubeStateID.NullState)
            {
                Debug.LogWarning("当前状态ID : CubeStateID为空:" + id);
                return;
            }
    
            if (mMap.ContainsKey(trans))
            {
                Debug.LogWarning("当前状态:" + trans +" 已经添加过了");
                return;
            }
            mMap.Add(trans,id);
        }
    
        public void DelectTransition(CubeTransition trans)
        {
            if (mMap.ContainsKey(trans) == false)
            {
                Debug.LogError("删除转换条件的时候, 转换条件:[" + trans + "]不存在");
                return;
            }
            mMap.Remove(trans);
        }
    
        public CubeStateID GetOutPutStateID(CubeTransition trans)
        {
            if (mMap.ContainsKey(trans) == false)
            {
                Debug.LogWarning("当前状态 :"+ trans +" 的ID为空状态:" + mMap[trans]);
                return CubeStateID.NullState;
            }
            else
            {
                return mMap[trans];
            }
        }
    
        public virtual void DoBeforeEntering() { }
        public virtual void DoBeforeLeaving() { }
    
        public abstract void Reason(List<Enemy> targets);
        public abstract void Act(List<Enemy> targets);
    
    }
    

    FSMSystem类代表有限状态机类。
    它具有NPC拥有的状态的列表以及添加,删除状态以及更改计算机所处的当前状态的方法。

    public class CubeFSMSystem
    {
        private List<ICubeState> States = new List<ICubeState>();
    
        protected ICubeState currentState;
        public ICubeState CurrentState { get { return currentState; } }
    
        public void AddState(ICubeState state)
        {
            Debug.Log(state.StateID);
            if (state == null)
            {
                Debug.LogError("要添加的状态为空");
                return;
            }
            if (States.Count == 0)
            {
                States.Add(state);
                currentState = state;
                return;
            }
            foreach (ICubeState s in States)
            {
                if (s.StateID == state.StateID)
                {
                    Debug.LogError("要添加的状态ID[" + s.StateID + "]已经添加");
                    return;
                }
            }
            States.Add(state);
        }
    
        public void DelectState(CubeStateID stateID)
        {
            if (stateID == CubeStateID.NullState)
            {
                Debug.LogError("要删除的状态ID为空" + stateID); return;
            }
            foreach (ICubeState s in States)
            {
                if (s.StateID == stateID)
                {
                    States.Remove(s);
                    return;
                }
            }
            Debug.LogError("要删除的StateID不存在集合中:" + stateID);
        }
    
        public void PerformTransition(CubeTransition trans)
        {
            if (trans == CubeTransition.NullTansition)
            {
                Debug.LogError("要执行的转换条件为空 : " + trans); return;
            }
            CubeStateID nextStateID = currentState.GetOutPutStateID(trans);
            if (nextStateID == CubeStateID.NullState)
            {
                Debug.LogError("在转换条件 [" + trans + "] 下,没有对应的转换状态"); return;
            }
            foreach (ICubeState s in States)
            {
                if (s.StateID == nextStateID)
                {
                    currentState.DoBeforeLeaving();
                    currentState = s;
                    currentState.DoBeforeEntering();
                    return;
                }
            }
        }
    
    
    }
    

    角色的Idle (空闲)状态:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CubeIdleState : ICubeState
    {
        public CubeIdleState(CubeFSMSystem fsm, CubePlayer player) : base(fsm, player)
        {
            mStateID = CubeStateID.Idle;
        }
    
        public override void Act(List<Enemy> targets)
        {
            Debug.Log("播放 Idle 动画中....");
        }
    
        public override void Reason(List<Enemy> targets)
        {
            if (targets != null && targets.Count > 0)
            {
                mFSM.PerformTransition(CubeTransition.SeeEnemy);
            }
        }
    }
    

    角色的Chase(追击敌人) 状态

    public class CubeChaseState : ICubeState
    {
        public CubeChaseState(CubeFSMSystem fsm, CubePlayer player) : base(fsm, player)
        {
            mStateID = CubeStateID.Chase;
        }
    
        public override void Act(List<Enemy> targets)
        {
            if (targets != null || targets.Count > 0)
            {
                mPlayer.MoveTo(targets[0].transform.position);
            }
        }
    
        public override void Reason(List<Enemy> targets)
        {
            if (targets == null || targets.Count == 0)
            {
                mFSM.PerformTransition(CubeTransition.NoEnemy);
                return;
            }
            float distance = Vector3.Distance(mPlayer.transform.position, targets[0].transform.position);
            if (distance <= mPlayer.attackRange)
            {
                mFSM.PerformTransition(CubeTransition.CanAttack);
            }
        }
    }
    

    角色的Attack (攻击)状态:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CubeAttackState : ICubeState
    {
        public CubeAttackState(CubeFSMSystem fsm, CubePlayer player) : base(fsm, player)
        {
            mStateID = CubeStateID.Attack;
        }
    
        private float mAttackTime = 1;
        private float mAttackTimer = 1;
    
        public override void Act(List<Enemy> targets)
        {
            if (targets == null || targets.Count == 0) return;
            mAttackTimer += Time.deltaTime;
            if (mAttackTimer > mAttackTime)
            {
                mPlayer.Attack(targets[0]);
                mAttackTimer = 0;
            }
        }
    
        public override void Reason(List<Enemy> targets)
        {
            if (targets == null || targets.Count == 0)
            {
                mFSM.PerformTransition(CubeTransition.NoEnemy);
                return;
            }
            float distance = Vector3.Distance(mPlayer.transform.position, targets[0].transform.position);
            if (distance > mPlayer.attackRange)
            {
                mFSM.PerformTransition(CubeTransition.SeeEnemy);
            }
        }
    
    }
    

    角色类:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    
    public class CubePlayer : MonoBehaviour {
    
        public float attackRange = 10;
        private NavMeshAgent mNavAgent;
        private CubeFSMSystem mFsmSystem;
    
        private void Awake()
        {
            MakeFSM();
            mNavAgent = GetComponent<NavMeshAgent>();
        }
    
        private void Update()
        {
            if (GameController.Instance.enemyList.Count == 0 || GameController.Instance.enemyList == null)
                return;
            mFsmSystem.CurrentState.Reason(GameController.Instance.enemyList);
            mFsmSystem.CurrentState.Act(GameController.Instance.enemyList);
        }
    
        public void MakeFSM()
        {
            mFsmSystem = new CubeFSMSystem();
    
            CubeIdleState cubeIdleState = new CubeIdleState(mFsmSystem,this);
            cubeIdleState.AddTransition(CubeTransition.SeeEnemy,CubeStateID.Chase);
    
            CubeChaseState cubeChaseState = new CubeChaseState(mFsmSystem, this);
            cubeChaseState.AddTransition(CubeTransition.NoEnemy,CubeStateID.Idle);
            cubeChaseState.AddTransition(CubeTransition.CanAttack,CubeStateID.Attack);
    
            CubeAttackState cubeAttackState = new CubeAttackState(mFsmSystem, this);
            cubeAttackState.AddTransition(CubeTransition.NoEnemy, CubeStateID.Idle);
            cubeAttackState.AddTransition(CubeTransition.SeeEnemy, CubeStateID.Chase);
    
            mFsmSystem.AddState(cubeIdleState);
            mFsmSystem.AddState(cubeChaseState);
            mFsmSystem.AddState(cubeAttackState);
        }
    
        public void Attack(Enemy enemy)
        {
            transform.LookAt(enemy.transform.position);
            Debug.Log("播放攻击动画....");
        }
    
        public void MoveTo(Vector3 targetPosition)
        {
            mNavAgent.SetDestination(targetPosition);
            Debug.Log("播放行走动画....");
        }
    }
    

    游戏控制者类:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    
    public class GameController : MonoBehaviour
    {
    
        private static GameController _instance;
        public static GameController Instance { get { return _instance; } }
        public GameObject enemy;
        public List<Enemy> enemyList = new List<Enemy>();
    
        public void Awake()
        {
            _instance = this;
        }
    
        private void Update()
        {
            SpawnEnemy();
        }
    
        public void SpawnEnemy()
        {
            if (Input.GetKeyDown(KeyCode.M))
            {
                GameObject itemGo = GameObject.Instantiate(enemy);
                itemGo.transform.position = Vector3.zero;
                enemyList.Add(itemGo.GetComponent<Enemy>());
            }
        }
    }
    

    敌人类:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    
    public class Enemy : MonoBehaviour {
    
        private NavMeshAgent navMeshAgent;
        public Transform targetPos;
    
        private void Start()
        {
            navMeshAgent = GetComponent<NavMeshAgent>();
            navMeshAgent.SetDestination(targetPos.position);
        }
    
        private void Update()
        {
            
        }
    }

    自行设置出生点位置 和  角色(Cube) 和敌人(Enemy) 并添加导航组件且烘培,即可实现FSM状态机的简单实现

    相关资料:http://wiki.unity3d.com/index.php/Finite_State_Machine

     

     

     

    展开全文
  • FSM有限状态机学习及Unity3D案例讲解

    千次阅读 2018-04-08 17:31:55
    遂今日更新FSM有限状态机学习,希望大家共同进步! 开发版本:Unity 2017.1.1f1、VS 2017 适合人群:初学Unity者 一.有限状态机定义 有限状态机(英文:Finite State Machine,简称FSM),是指在不同阶段呈现不同的...

    引言:近日忙于毕业论文,今天看到涨了3个粉丝,不甚惊喜。遂今日更新FSM有限状态机学习,希望大家共同进步!

    开发版本:Unity 2017.1.1f1、VS 2017

    适合人群:初学Unity者

    一.有限状态机定义

    有限状态机(英文:Finite State Machine,简称FSM),是指在不同阶段呈现不同的运行状态的系统,这些状态是有限的,不重叠的。这样的系统在某一时刻一定会处于其中所有状态中的一个状态,此时它接收一部分的输入,产生相应的响应,并且迁移到可能的状态。

        一般有限状态机有一下几种类型的动作:
        1.进入动作:进入当前状态时执行

        2.退出动作:退出当前状态时执行

        3.输入动作:在当前状态时执行
        4.转移动作:在进行特定切换状态时执行

        有限状态机提供了描述和控制应用逻辑的强大方法,可以应用于控制NPC行为,图形界面管理等方面。FSM可以使得各个状态之间相互独立,互不影响,避免了状态与状态之间的耦合度,具有规则简单,可读性和可验证性等优点。

     

    二.整理思路

    简单的有限状态机就是switch语句,但如果状态过多的情况下,switch会使得代码显得臃肿,可扩展性很低。

    假设敌人有四种状态,Idle、Patrol、Chase、Attack,switch实现方法如下:

    public enum States
    {
        Idle,//空闲状态
        Patrol,//巡逻状态
        Chase,//追逐状态
        Attack//攻击状态
    }
    
    public class SimpleFSM : MonoBehaviour
    {
        private States currentState = States.Idle;
    
        private void Update()
        {
            switch (currentState)
            {
                case States.Idle:
                    //TODO 空闲状态动作
                    break;
                case States.Patrol:
                    //TODO 巡逻状态动作
                    break;
                case States.Chase:
                    //TODO 追逐状态动作
                    break;
                case States.Attack:
                    //TODO 攻击状态动作
                    break;
            }
        }
    }

    接下来整理“高级的”有限状态机实现方法,FSM由状态类和管理类组成,先创建一个状态基类FSMState,用于实现状态类的基本方法,每添加一种状态,就作为它的子类。然后,用一个管理类FSMSystem把所有状态管理起来,方便使用状态机。FSM类图如下所示:

    三.实现代码

    1.定义枚举类型

    public enum StateID
    {
        NullStateID,
    }
    public enum Transition
    {
        NullTransition
    }

    定义每一种状态的ID和状态之间的转换条件

    2.FSMState基类

    public abstract class FSMState
    {
        protected StateID stateID;
        public StateID ID { get { return this.stateID; } }
        protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
        protected FSMSystem fsm;
    
        public FSMState(FSMSystem fsm)
        {
            this.fsm = fsm;
        }
    
        /// <summary>
        /// 添加转换条件
        /// </summary>
        /// <param name="trans">转换条件</param>
        /// <param name="stateID">转换的目标状态</param>
        public void AddTransition(Transition trans, StateID stateID)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError(trans + "为空,转换条件不允许为空");return;
            }
            if (stateID == StateID.NullStateID)
            {
                Debug.LogError(stateID + "为空,状态ID不允许为空"); return;
            }
            if (map.ContainsKey(trans))
            {
                Debug.LogError(trans + "已经存在,请查看该转换条件是否正确");
            }
            else
            {
                map.Add(trans, stateID);
            }
        }
    
        /// <summary>
        /// 删除转换条件
        /// </summary>
        /// <param name="trans">需删除的转换条件</param>
        public void DeleteTransition(Transition trans)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError(trans + "为空,转换条件不允许为空"); return;
            }
            if (map.ContainsKey(trans) == false)
            {
                Debug.LogError(trans + "不存在,请查看该转换条件是否正确"); 
            }
            else
            {
                map.Remove(trans);
            }
        }
    
        /// <summary>
        /// 通过转换条件,得到目标状态
        /// </summary>
        /// <param name="trans">转换条件</param>
        /// <returns>返回目标状态</returns>
        public StateID GetTargetStateID(Transition trans)  
        {
            if (map.ContainsKey(trans) == false)
            {
                Debug.LogError(trans + "不存在,请查看该转换条件是否正确");
                return StateID.NullStateID;
            }
            else
            {
                return map[trans];
            }
        }
    
        public virtual void DoBeforeEntering() { }//进入动作
        public virtual void DoAfterLeaving() { }//离开动作
        public abstract void Act();//输入动作
        public abstract void Reason();//转移动作
    }
    

    状态类主要存储转换条件和转换状态的字典,可以添加删除转换条件,根据条件返回对应的状态,并定义状态类的四种动作。

    3.FSMSystem管理类

    public class FSMSystem
    {
        private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();
        private FSMState currentState;
    
        /// <summary>
        /// 更新当前状态行为
        /// </summary>
        public void UpdateFSM()
        {
            currentState.Act();
            currentState.Reason();
        }
    
        /// <summary>
        /// 添加状态
        /// </summary>
        /// <param name="state">需管理的状态</param>
        public void AddState(FSMState state)
        {
            if (state == null)
            {
                Debug.LogError(state + "为空"); return;
            }
            if (currentState == null)
            {
                currentState = state;
            }
            if (states.ContainsValue(state))
            {
                Debug.LogError(state + "已经存在");
            }
            else
            {
                states.Add(state.ID, state);
            }
        }
    
        /// <summary>
        /// 删除状态
        /// </summary>
        /// <param name="id">需要删除状态的ID</param>
        /// /// <returns>删除成功返回true,否则返回false</returns>
        public bool DeleteState(StateID id)
        {
            if (id == StateID.NullStateID)
            {
                Debug.LogError(id + "为空");
                return false;
            }
            if (states.ContainsKey(id) == false)
            {
                Debug.LogError(id + "不存在");
                return false;
            }
            else
            {
                states.Remove(id);
                return true;
            }
        }
    
        /// <summary>
        /// 执行转换
        /// </summary>
        /// <param name="trans">转换条件</param>
        public void PerformTransition(Transition trans)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError(trans + "为空");return;
            }
            StateID targetID = currentState.GetTargetStateID(trans);
            if (states.ContainsKey(targetID) == false)
            {
                Debug.LogError(targetID + "不存在");return;
            }
            FSMState targetState = states[targetID];
            currentState.DoAfterLeaving();
            targetState.DoBeforeEntering();
            currentState = targetState;
        }
    }

     

    FSMSystem用来管理各个状态,字典存储ID和对应的状态,可以添加删除状态,并执行状态转换。

    四.案例讲解

    假设敌人按照路线巡逻,当发现玩家的时候,开始追逐。但玩家跑出追击范围的时候,敌人继续回去巡逻。

    项目的源文件在文末,有需要的童鞋可以自行下载。

     

    敌人巡逻效果如下:

    敌人发现玩家开始追逐,当玩家逃离后,返回继续巡逻,效果如下:

     

    分析此时敌人状态有两种,巡逻和追逐,转换条件也对应有两种

    public enum StateID
    {
        NullStateID,
        PatrolState,
        ChaseState
    }
    public enum Transition
    {
        NullTransition,
        FindPlayer,
        LosePlayer
    }

     

    创建两个子类PatrolState和ChaseState都继承自FSMState,分别用来实现巡逻和追逐的状态行为。

    在Enemy类中,实例化FSMSystem对象,添加巡逻和追逐状态,还有之间的转换条件

    public class Enemy : MonoBehaviour
    {
        private FSMSystem fsm;
    
        private void Start()
        {
            fsm = new FSMSystem();
            FSMState patrolState = new PatrolState(fsm);
            FSMState chaseState = new ChaseState(fsm);
            fsm.AddState(patrolState);
            fsm.AddState(chaseState);
            patrolState.AddTransition(Transition.FindPlayer, StateID.ChaseState);
            chaseState.AddTransition(Transition.LosePlayer, StateID.PatrolState);
        }
    
        private void Update()
        {
            fsm.UpdateFSM();
        }
    }
    

     

    FSM有限状态机除了实现敌人的行为外,还可以用来管理UI界面的切换,使用方式基本相似。如果大神发现我分享的学习记录中有错误,还请不吝赐教。

    案例百度云链接:链接:https://pan.baidu.com/s/1MVpKQ5U5eJE7zJTMXSMj3A  提取码:coh5 

    觉得我分享的学习记录不错的,点赞关注我哦!

     

     

    展开全文
  •     总的来说,有限状态机系统,是指在不同阶段会呈现出不同的运行状态的系统,这些状态是有限的、不重叠的。...CS 角色FSM图     使用switch (){case….}实现简单的有限状态机。 ...

        总的来说,有限状态机系统,是指在不同阶段会呈现出不同的运行状态的系统,这些状态是有限的、不重叠的。这样的系统在某一时刻一定会处于其所有状态中的一个状态,此时它接收一部分允许的输入,产生一部分可能的响应,并且迁移到一部分可能的状态。
         五个要素:状态,事件,条件,动作,迁移

    CS 角色FSM图


    这里写图片描述

        使用switch (){case….}实现简单的有限状态机。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class SimleFSM : MonoBehaviour {
        public enum State
        {
            Idle,
            Patrol,
            Chase,
            Attack
        }
        private State state = State.Idle;
        void Update () {
            switch (state)
            {
                case State.Idle:
                    ProcessStateIdle();
                    break;
                case State.Patrol:
                    ProcessStatePatrol();
                    break;
                case State.Chase:
                    ProcessStateChase();
                    break;
                case State.Attack:
                    ProcessStateAttack();
                    break;
                default:
                    break;
            }
        }
    
        void ProcessStateIdle()
        {
        }
        void ProcessStatePatrol()
        {
        }
        void ProcessStateChase()
        {
        }
        void ProcessStateAttack()
        {
        }
    }
    

        Unity中FSM有限状态机系统的构成和功能的简单实现:


    这里写图片描述

    
    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 Update(GameObject npc)
        {
            currentState.Act(npc);
            currentState.Reason(npc);
        }
    
        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 trans)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError("无法执行空的转换条件");return;
            }
            StateID id= currentState.GetOutputState(trans);
            if (id == StateID.NullStateID)
            {
                Debug.LogWarning("当前状态" + currentStateID + "无法根据转换条件" + trans + "发生转换");return;
            }
            if (states.ContainsKey(id) == false)
            {
                Debug.LogError("在状态机里面不存在状态" + id + ",无法进行状态转换!");return;
            }
            FSMState state = states[id];
            currentState.DoAfterLeaving();
            currentState = state;
            currentStateID = id;
            currentState.DoBeforeEntering();
        }
    } 
    
    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 trans,StateID id)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError("不允许NullTransition");return;
            }
            if (id == StateID.NullStateID)
            {
                Debug.LogError("不允许NullStateID"); return;
            }
            if (map.ContainsKey(trans))
            {
                Debug.LogError("添加转换条件的时候," + trans + "已经存在于map中");return;
            }
            map.Add(trans, id);
        }
        public void DeleteTransition(Transition trans)
        {
            if (trans == Transition.NullTransition)
            {
                Debug.LogError("不允许NullTransition"); return;
            }
            if (map.ContainsKey(trans)==false)
            {
                Debug.LogError("删除转换条件的时候," + trans + "不存在于map中"); return;
            }
            map.Remove(trans);
        }
        public StateID GetOutputState(Transition trans)
        {
            if (map.ContainsKey(trans))
            {
                return map[trans];
            }
            return StateID.NullStateID;
        }
    
        public virtual void DoBeforeEntering() { }
        public virtual void DoAfterLeaving() { }
        public abstract void Act(GameObject npc);
        public abstract void Reason(GameObject npc);
    }
    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Enemy : MonoBehaviour {
    
        private FSMSystem fsm;
    
        void Start () {
            InitFSM();
        }
    
        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;
    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 pathTransform = GameObject.Find("Path").transform;
            Transform[] children= pathTransform.GetComponentsInChildren<Transform>();
            foreach(Transform child in children)
            {
                if (child != pathTransform)
                {
                    path.Add(child);
                }
            }
            playerTransform = GameObject.Find("Player").transform;
        }
    
        public override void Act(GameObject npc)
        {
            npc.transform.LookAt(path[index].position);
            npc.transform.Translate(Vector3.forward * Time.deltaTime * 3);
            if (Vector3.Distance(npc.transform.position, path[index].position) < 1)
            {
                index++;
                index %= path.Count;
            }
        }
    
        public override void Reason(GameObject npc)
        {
            if (Vector3.Distance(playerTransform.position, npc.transform.position) < 3)
            {
                fsm.PerformTransition(Transition.SeePlayer);
            }
        }
    }
    
    using System;
    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 npc)
        {
            npc.transform.LookAt(playerTransform.position);
            npc.transform.Translate(Vector3.forward * 2 * Time.deltaTime);
        }
        public override void Reason(GameObject npc)
        {
            if (Vector3.Distance(playerTransform.position, npc.transform.position) > 6)
            {
                fsm.PerformTransition(Transition.LostPlayer);
            }
        }
    }
    
    展开全文
  • Unity下简易状态机(FSM)的实现

    千次阅读 2015-10-02 20:59:28
    Unity 下简易状态机的实现国庆到处都是人,我的建议是要么出国旅游,要么就宅在家把时间留给自己或家人。朋友约我去星巴克坐着重构代码,想想也是程序猿之间才有的默契。关于状态机,我想都知道它很常用,就像单例...
  • unity3D FSM有限状态机(状态设计模式)

    万次阅读 多人点赞 2018-07-12 14:07:50
    FSM简单来说就是 4个类 1. 状态基类 状态基类需要3个虚方法,以及虚拟机对象 2. 拥有者泛型类 继承状态基类,构造出使用者对象 3. 玩家脚本类 在Start方法里构造new各个状态机类(传入枚举id,使用者this...
  • Unity--FSM有限状态机

    千次阅读 2018-08-10 15:28:05
    有限状态机最核心的两个脚本是FSMState和FSMSystem,其中FSMState是状态基类,FSMSystem是状态机的管理类,这两个脚本可以在Wiki.unity3d.com里搜索State找到,一个17k的文件。 在FSMState类中,有两个枚举,第一...
  • Unity状态机FSM

    2021-04-20 16:08:16
    Unity状态机FSM 一:状态机介绍 有限状态机,也称为 FSM(Finite State Machine) ,这些状态是有限的、不重叠的,其在任意时刻都处于有限状态集合中的某一状态。当其获得特定输入时,将从当前状态转换到另一个状态 ...
  • UnityFSM-源码

    2021-03-31 23:14:43
    UnityFSM
  • 在启动一个FSM时,首先必须将FSM置于“起始状态”,然后输入一系列操作,最终,FSM会到达“结束状态” 实现一个简单的状态机 ///定义一个抽象的类,具体的函数在子类中实现,是状态机的基类 public abstruct class ...
  • Unity FSM有限状态机

    2020-05-22 22:36:51
    https://blog.csdn.net/a592733740/article/details/106292148
  • 基于FSMUnity3D游戏动画系统的设计与实现,陈玲鸿,黄小军,本文给出了基于FSMUnity3D游戏引擎的动画系统的一种新的解决方案。用FSM技术实现智能管理动画系统,并结合Unity3D游戏开发引擎,通过�
  • Enermy_C#_FSM_unity_源码

    2021-10-03 17:31:04
    利用有限状态机实现游戏中的简易敌人AI.
  • Unity中实现FSM有限状态机

    千次阅读 2017-01-09 21:27:50
    简介 有限状态机,(英语:Finite-state machine, FSM),又称有限状态...有限状态机(FSM)是游戏AI的一种常用模型,我做一个简单的记录,在Unity中实现有限状态机模型. FSM的结构和逻辑 整体结构分为4个部分 AIContr
  • 当然无论是FSM、行为树、亦或者简单粗暴的ifelse都能制作AI,但是考虑到FSM比ifelse、switch架构更清晰方便管理,比行为树更好把控(毕竟自己纯手撸代码),最后决定使用FSM。 核心代码 FSM管理类 using System; ...
  • FSM AI Template v1.1.0.unitypackage
  • 有限状态机、FSM,会经常说到,那它究竟是什么? 有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。状态机并...
  • using System.Collections; using System.Collections.Generic; using UnityEngine; public class StoneIdle : FSMBase { Animator animator; public StoneIdle(Animator animator) ... this.animator = animator;...
  • FSM_Test.unitypackage

    2021-06-15 10:29:39
    FSM有限状态机
  • FSM 用C#编写的分层有限状态机。
  • 有限状态机FSM

    2018-09-19 04:52:25
    Unity C# 《有限状态机》的用法教程详解Demo 助力快速理解 FSM 有限状态机,完成游戏状态的切换 教程地址:https://blog.csdn.net/ChinarCSDN/article/details/82263126
  • 2,代码实现有限状态机 第一步,创建一个脚本,定义一个接口IState,用来声明一种状态的运行周期,如果你了解Unity脚本生命周期,很清楚代码三个方法代表的意义,如果你不了解也没有关系,我在下面列出了三个方法的...
  • 实现的功能:AI在固定的路径上巡逻,当玩家靠近AI的视野范围时,AI会追击玩家。...FSM基类: using System.Collections; using System.Collections.Generic; using UnityEngine; //状态转化的条件枚举 public enum Tra
  • FSM 有限状态机 概念 如其名,在有限的状态下,管理状态的转移的一种设计模式 基本思路 如 状态a 要切换到 状态b,需要通过中介也就是状态管理机进行切换,而不是两种状态直接切换,降低了耦合 另外每种状态...
  • All of you, the community, are freaking ... We have almost 2.5 million registered Unity users and quite a few of you, correction, a tonne of you help each other out. This weekend one of our long ...
  •  AI FSMs 的工作与Unity的的Animation FSMs,在那里一个动画状态将更改为另一个符合的要求。可以通过使用第三方插件像行为实施 AI FSM 或它可以直接由脚本以及执行。 若要获取有限状态机框架的基本理念,我们将执行...
  • FSM 精简版

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,099
精华内容 439
关键字:

fsmunity