Unity的状态机设计

本人新手,随便写写而已。

本文通过一个实例实现了在Unity下的有限状态机(参考了wiki上的教程)。

有限状态机是一个设备具有有限数量的状态,他可以在任何时间根据输入进行操作,使得一个状态进入另个一个状态。一个状态机在任何瞬间只能处于一种状态。

具体可以参考  状态设计模式。

本例是这样一种状态装换。

游戏人物NPC在空闲时处于巡逻状态,当看见Player在视野内的时候,转入转入追逐Player状态;一旦和Player距离拉大,便返回巡逻状态。

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
//无论是NPC还是Player都有很多状态,在状态切换的时候为了使得程序显得清晰明了,采用了状态机制
//首先实际状态都是继承自某个状态抽象类的,这个抽象类定义了进入,退出一个状态虚方法
//定义了检测环境是否发生状态改变,以及在该状态下执行的动作的抽象方法
// 该实例主要涉及到一个NPC在指定的位置进行巡逻,当看到Playeer的时候切换状态进入追逐Player状态public enum Translate    //如果进入一个新的状态,需要一些触发,比如NPC看到了Player,由巡逻状态进入跟踪状态
{                        NullTrans,SeePlayer,LosePlayer}public enum StateID     //每个状态都应该有一个ID,作为识别改状态的标志
{ NullState,Chaseingplayer,FollowPath}public abstract class FMS_State    //定一个抽象类
{private StateID id;            //定一个状态ID作为变量来标识public StateID ID{set { id = value; }get { return id; }}private Dictionary<Translate, StateID> map = new Dictionary<Translate, StateID>();    //在某一状态下,事件引起了触发进入另一个状态
// 于是我们定义了一个字典,存储的便是触发的类型,以及对应要进入的状态public void addDictionary(Translate tr, StateID id1)  //向字典里添加{if (tr == Translate.NullTrans){Debug.LogError("Null Trans is not allower to adding into");return;}if (ID == StateID.NullState){Debug.LogError("Null State id not ~~~");return;}if (map.ContainsKey(tr))              //NPC  任何时候都只能出于一种状态,所以一旦定义了一个触发的枚举类型,对应的只能是接下来的一种状态{Debug.LogError(id1.ToString() + "is already added to");return;}map.Add(tr, id1);}public void deleateDictionary(Translate tr) //删除字典里存储的一个状态{if (tr == Translate.NullTrans){Debug.LogError("TransNull is not allowed to delate");return;}if (map.ContainsKey(tr)){map.Remove(tr);return;}Debug.LogError(tr.ToString() + "are not exist");}public StateID GetOutState(Translate tr)  //由状态的触发枚举类型返回一个对应的状态类型{if (map.ContainsKey(tr)){// Debug.Log("Translate " + tr + "State" + map[tr]);return map[tr];}return StateID.NullState;}public virtual void DoBeforeEnter() { }    //虚方法public virtual void DoBeforeMoveing() { }public abstract void Reason(GameObject player, GameObject NPC); //  抽象方法public abstract void Act(GameObject player, GameObject NPC);}

随后根据这个基类派生出巡逻类,和追逐类。

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
public class Follow_State:FMS_State  //派生出一个巡逻的类
{private GameObject[] waypoints;    //在这些位置巡逻private int currentWayPoint;    public Follow_State(GameObject[] ob){waypoints= ob;  currentWayPoint = 0;ID = StateID.FollowPath;        //当前状态的ID}public override void Reason(GameObject player, GameObject NPC)    //与环境交互,来判断是否需要状态切换{RaycastHit hit;if(Physics.Raycast(NPC.transform.position,NPC.transform.forward,out hit ,15)){if(hit.transform.tag=="Player"){FMS_Machine_Manage.GetInstance.changeState(Translate.SeePlayer);}}}public override void Act(GameObject player, GameObject NPC)   //在该状态下改做点什么呢{Vector3 vel = NPC.rigidbody.velocity;Vector3 dir =waypoints[currentWayPoint].transform.position- NPC.transform.position;if(dir.magnitude<1){currentWayPoint++;// Debug.Log("currentwappoint " + currentWayPoint);if(currentWayPoint>=waypoints.Length){currentWayPoint = 0;}}else{vel = dir.normalized*10;NPC.transform.rotation = Quaternion.Lerp(NPC.transform.rotation, Quaternion.LookRotation(dir), Time.deltaTime * 5);NPC.transform.eulerAngles = new Vector3(0, NPC.transform.localEulerAngles.y, 0);}NPC.rigidbody.velocity = vel;}public override void DoBeforeMoveing(){}public override void DoBeforeEnter(){}
}

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;public class Chaseing_State : FMS_State {   //派生出了一个追逐类public Chaseing_State(){ID = StateID.Chaseingplayer;   //定义  状态ID}public override void Reason(GameObject player, GameObject NPC){if(Vector3.Distance(player.transform.position,NPC.transform.position)>=5){FMS_Machine_Manage.GetInstance.changeState(Translate.LosePlayer);}}public override void Act(GameObject player, GameObject NPC){Vector3 vel = NPC.rigidbody.velocity;Vector3 moveDir = player.transform.position - NPC.transform.position;NPC.transform.rotation = Quaternion.Lerp(NPC.transform.rotation, Quaternion.LookRotation(moveDir), Time.deltaTime * 5);NPC.transform.eulerAngles = new Vector3(0, NPC.transform.eulerAngles.y, 0);vel = moveDir * 3;NPC.rigidbody.velocity = vel;}    }

通常对状态的管理,我们会建立一个stateMachine来管理。

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
//状态管理类,对状态进行管理public class FMS_Machine_Manage:MonoBehaviour
{private List<FMS_State> states;//存储所有状态的的Listprivate FMS_State currentState;  //当前状态private StateID currentStateID;//当前状态IDpublic FMS_State CurrentState {set { currentState = value; }get { return currentState; } }public StateID CurrentStateID {set { currentStateID = value; }get { return currentStateID; } }public GameObject player;public GameObject[] path;public GameObject NPC;private static  FMS_Machine_Manage instance;public static  FMS_Machine_Manage GetInstance{get {if (instance == null){// instance = new FMS_Machine_Manage(); GameObject n = new GameObject();n.name = "FMS_Machine_Manage"; instance = n.AddComponent<FMS_Machine_Manage>() as FMS_Machine_Manage;}return instance;}}public void UpdateFunction(){CurrentState.Reason(player, NPC);CurrentState.Act(player, NPC);}public void Revert(){ }void Awake(){states = new List<FMS_State>();   //初始化NPC = GameObject.FindGameObjectWithTag("NPC");player = GameObject.FindGameObjectWithTag("Player");path = GameObject.FindGameObjectsWithTag("path");}public void MakeFMSMachine(){Follow_State follow = new Follow_State(path);follow.addDictionary(Translate.SeePlayer, StateID.Chaseingplayer);Chaseing_State chase = new Chaseing_State();chase.addDictionary(Translate.LosePlayer, StateID.FollowPath);GetInstance. AddFmsState(follow);GetInstance. AddFmsState(chase);}public void AddFmsState(FMS_State s)//注册所有状态{if (s == null){Debug.LogError(" Null reference is not allowed");}if (states.Count == 0){states.Add(s);                   //设置默认状态(important);currentState = s;currentStateID = s.ID;return;}foreach (FMS_State state in states){if (state == s){Debug.LogError(s.ID.ToString() + "has already been added");return;}}states.Add(s);}public void delateFmsState(StateID id){if (id == StateID.NullState){Debug.LogError("NullStateID is not allowed for a real state");return;}foreach (FMS_State state in states){if (state.ID == id){states.Remove(state);return;}}}public void changeState(Translate tr)           //更改状态{if (tr == Translate.NullTrans){Debug.LogError("NullTransition is not allowed for a real transition");return;}//if (currentState.GetOutState(tr) == StateID.NullState)//{//    Debug.Log("translate" + "          " + tr + "           " + currentState.GetOutState(tr)+"         "+CurrentStateID);//    Debug.LogError("1234");//    return;//}StateID id = CurrentState.GetOutState(tr);   //当前状态会进入的新的状态currentStateID = id;//    Debug.Log("Prives" + Prives.ID);foreach (FMS_State state in states)          //通过注册的所有状态,进行搜索来获取要进入的状态实例{if (currentStateID == state.ID){CurrentState.DoBeforeMoveing();     //退出状态前,留下点什么,比如挥舞下手臂currentState = state;CurrentState.DoBeforeEnter();     //进入状态break;}}}}

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;public class NPC_Control : MonoBehaviour {public void Start(){FMS_Machine_Manage.GetInstance.MakeFMSMachine();}public void FixedUpdate(){FMS_Machine_Manage.GetInstance.UpdateFunction();}}

转载于:https://www.cnblogs.com/xiao-wei-wei/p/3526442.html

Unity的状态机设计相关推荐

  1. Unity UGUI开发设计及案例讲解

    Unity--UGUI开发设计及案例讲解 1. Unity4.6跟以前的版本的最大区别首先在于在层级视图中点鼠标右键时出现的弹出菜单上,它把以前许多的菜单项进行了归类,比如cube sphere ca ...

  2. FPGA 状态机设计

    数字系统有两大类有限状态机(Finite State Machine,FSM):Moore状态机和Mealy状态机. Moore状态机 其最大特点是输出只由当前状态确定,与输入无关.Moore状态机的 ...

  3. 状态机设计的一般步骤_浅谈状态机

    来源:公众号[ZYNQ]ID   :FreeZynq 整理 :李肖遥 本文目录 前言 状态机简介 状态机分类 Mealy 型状态机 Moore 型状态机 状态机描述 一段式状态机 二段式状态机 三段式 ...

  4. Unity应用架构设计(10)——绕不开的协程和多线程(Part 1)

    阅读目录 是否需要多线程? 协程的内部原理 小结 在进入本章主题之前,我们必须要了解客户端应用程序都是单线程模型,即只有一个主线程(Main Thread),或者叫做UI线程,即所有的UI控件的创建和 ...

  5. (32)FPGA米勒型状态机设计(三段式)(第7天)

    (32)FPGA米勒型状态机设计(三段式)(第7天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA米勒型状态机设计(三段式)(第7天) 5)技术交流 6 ...

  6. (31)FPGA米勒型状态机设计(二段式)(第7天)

    (31)FPGA米勒型状态机设计(二段式)(第7天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA米勒型状态机设计(二段式)(第7天) 5)技术交流 6 ...

  7. (30)FPGA米勒型状态机设计(一段式)(第6天)

    (30)FPGA米勒型状态机设计(一段式)(第6天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA米勒型状态机设计(一段式)(第6天) 5)技术交流 6 ...

  8. (29)FPGA摩尔型状态机设计(第6天)

    (29)FPGA摩尔型状态机设计(第6天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA摩尔型状态机设计(第6天) 5)技术交流 6)参考资料 2 FP ...

  9. 视频教程-Unity网络游戏架构设计-Unity3D

    Unity网络游戏架构设计 网名:海洋,CSDN社区讲师,3D游戏引擎开发者,IT讲师,计算机图形学方向研究生,曾在浙江大学CAD&CG;国家重点实验室学习.从事IT行业15年,主导或参与了1 ...

最新文章

  1. VS2015快捷键使用学习总结
  2. Bootstrap进度条
  3. 模拟一次CSRF(跨站请求伪造)例子,适合新手
  4. 2018年我国视频监控市场趋势:智能视频分析进入规模化
  5. 安卓手机挂载Linux,android 挂载NFS教程
  6. 深度linux系统反复重启,修复启动
  7. ElasticSearch多字段查询best_fieldsmost_fields
  8. 关于E-Prime 2.0 无法呈现音频的一种解决方案
  9. bugku 社工-初步收集
  10. 约瑟夫问题、约瑟夫环
  11. android 格式化sd咔_安卓手机怎么格式化内存(sd卡)?安卓手机格式化方法大全
  12. 什么是php-fpm
  13. 编译原理之Frist集与Follow集
  14. 普通路由器改4g路由器_4G工业路由器物联卡批发价格是多少?良心厂家推荐
  15. SpringBoot入门系列(二)如何返回统一的Json数据格式
  16. 2020第二周美赛感想
  17. Manjaro 个人新装配置
  18. 2天,我把MySQL索引、锁、事务、分库分表撸干净了!
  19. antd vue 树更新数据后不展开_Vue 性能优化 - 去除 VNode
  20. 数据库分片(Database Sharding)

热门文章

  1. mysql5.6 install_mysql5.6安装
  2. vscode设置背景图片
  3. C语言 main函数参数 argc,argv 用处,控制台应用程序模板2
  4. 【w3cschool】通过C语言类比快速上手C#
  5. python 3.6.0新语法,Python 3.6学习笔记(附2018最新python初学者入门视频教学)
  6. 五角星是不是旋转对称图形_新部编二年级下册数学第10单元总复习教案,克和千克、图形的运动...
  7. Lc5-最长回文字串
  8. Nyoj 737: 石子合并(一)(区间DP+四边形优化)
  9. bzoj 2599: [IOI2011]Race(树的点分治)
  10. bzoj 1086: [SCOI2005]王室联邦(DFS)