先看下效果:

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的玩家一靠近就会追赶了,追不上就返回继续巡逻了。

Unity FSM(有限状态机)相关推荐

  1. Unity下FSM有限状态机详解

    FSM有限状态机详解 文章目录 FSM有限状态机详解 FSM的定义 FSM的适用性 FSM的设计分析 状态转换表的使用 状态和条件的标识符Id 条件基类的设计 FSMTrigger 状态基类的设计 F ...

  2. FSM有限状态机学习及Unity3D案例讲解

    引言:近日忙于毕业论文,今天看到涨了3个粉丝,不甚惊喜.遂今日更新FSM有限状态机学习,希望大家共同进步! 开发版本:Unity 2017.1.1f1.VS 2017 适合人群:初学Unity者 一. ...

  3. Unity编程有限状态机的实现

    Unity编程有限状态机的实现 首先,为了避免浪费一些同学的时间,我对本次博客的内容进行说明.(避免一些同学白花时间没有找到自己想看的东西) 本次我的博客内容有 1.结合我本周所学,根据我自己对有限状 ...

  4. 游戏 AI 设计之 FSM 有限状态机

    FSM 有限状态机 一.概述 有限状态机(finite-state machine,缩写:FSM)又称有限状态自动机(finite-state automaton,缩写:FSA),简称状态机,是表示有 ...

  5. Lua FSM有限状态机的实现

    最近做项目,因为要将游戏的代码基本全部改成lua的,对c#层面的东西基本只要unity的生命周期就可以了.刚开始接触lua,心痒痒,决定上网买了<Lua游戏AI开发指南>看看,决定实现一个 ...

  6. unity3D FSM有限状态机(状态设计模式)

    前言 为了解决游戏过于麻烦的状态转换(人物动画过多),使用有限状态机. 缺点:代码量大 编写 使用多态和Switch new(状态设计模式) 类的介绍 PlyayCtrl:挂载在角色身上的脚本,用来控 ...

  7. 状态模式 - Unity(有限状态机)

    文章目录 状态模式(有限状态机) 结构 实现(有限状态机) 应用场景 优缺点 与其他模式的关系 状态模式(有限状态机) 状态模式是一种对象型模式,他将复杂的逻辑判断提取到不同状态对象中,允许状态对象在 ...

  8. Unity3D之FSM有限状态机

    1状态基类FSMstate的创建 1.1我们首先创建出来俩个全局枚举,用来保存当前状态的ID和转换的条件transition. 1.2 我们所以的状态类给抽象出来一个基类出来,在创建一个字典来保存转换 ...

  9. FSM有限状态机-状态图画法

    fsm包含三个组件:状态(必须有).动作(非必须).事件(非必须) 状态:体现当前状态机处在状态,比如,开状态,关状态等,同时状态有一个访问次数/visit的值,这个决定它需要触发多次才能发生状态转移 ...

最新文章

  1. 滇西应用技术大学计算机专业在哪里,滇西应用技术大学
  2. 微软System Center 2012推进私有云计算
  3. 多变量线性回归程序实现
  4. Linux的Page Cache
  5. org.junit.runners.model.InvalidTestClassError: Invalid test class ‘‘: 1. No runnable methods
  6. a标签里面设置onclick_HTML学习笔记:各种常用标签
  7. 【动态规划1】动态规划的引入(今天刷洛谷了嘛)
  8. 改变世界的iPhone背后都有些什么?
  9. 退出所有循环_探索未知种族之osg类生物---呼吸分解之事件循环三
  10. 通信原理第七版樊昌信 课后习题答案详解
  11. 【Unity3D插件】PUN 2插件分享《Unity3D多人在线联机联网插件》——客户端服务器端一体
  12. python应用学习(五)——requests爬取网页图片
  13. 专利交底书怎么写 -
  14. excel熵值法计算权重_由搜索权重排序引入的思考
  15. idea 2021版本错误提示反应慢
  16. 宁波大学2014年高等代数考研试题
  17. python画线段代码_python画线代码
  18. 电脑linux 开启热点hostapt,Ubuntu16.04开启热点
  19. 【Python编程】《Python学习手册》思维导图
  20. 转载 ps教程制作立体字

热门文章

  1. 西瓜书第六章笔记及答案——支持向量机
  2. 店大欺客?原来你是这样的亚马逊
  3. (每日一练java)CC12 拆分词句
  4. 数据分析 第八篇:OLS回归分析
  5. 请相信总有一扇门为你而开——社科院与杜兰大学金融管理硕士项目
  6. Vue+Element-ui实现emoji表情在光标处添加
  7. TRC免疫学丨艾美捷TRC关节炎研究领域
  8. 【JS】charAt()、fromCharCode() 与 charCodeAt()介绍
  9. 蓝牙RSSI定位入门到精通(2)--指纹法
  10. 众合云科旗下51社保荣获MeetHR Group十大影响力人力资源品牌奖