UNITY3D有限状态机
2016-05-09 09:47
357 查看
有限状态机是把一个对象的行为分解称为易于处理的“块”或状态。例如,灯的开关,就是一个简单的有限状态机。它有两种状态:开和关。
假想一个机器小猫。它在肚子有一个插槽,放有很多模块(用来控制小猫的状态)。这些模块里包含这小猫的不同行为。例如:玩毛线、吃鱼,或者睡觉。如果没有一个模块,小猫就会是一个死气沉沉的金属雕塑品,只会静静坐着。猫在玩毛线的状态时,会监控小猫饥饿的等级,当它感到饥饿等级上升时,会自己把模块转换到吃鱼。吃鱼模块运行,直到小猫吃饱后,再跳回玩毛线状态。这只小猫就是我们的程序,里面的模块就是程序里的各种状态。
2.为什么要用有限状态机
通常,在一个程序里面,转换各种状态,需要使用一系列的if-then语句或者switch语句。比如:While(游戏未结束)
{ Switch(游戏状态) Case 资源加载: Case 进入关卡: Load_gate();//加载背景、飞机、炮弹的图片。 Case 游戏菜单: If (游戏结束) 计算游戏结果 ase 游戏进行: New_paodan();//产生新炮弹 Move();//计算出该时刻飞机以及所有炮弹所在的位置 Is_pengzhuang();//碰撞判断 ase 游戏暂停: Thread_pause();//游戏暂停操作。 • Draw()函数框架的伪代码如下: Draw() { Switch(游戏状态) Case 游戏进行: Draw_background();//绘制背景 Draw_paodan();//画炮弹 Draw_feiji();//画飞机 Case 其他: 略.... } |
此外,当你想让对象处于初始进入状态或者退出状态时,你会常常需要一个状态完成一个制定的行动。例如,一个(敌人)对象进入逃跑状态,你可能会希望它挥着胳膊还道:啊!,当他最后逃脱并进入巡逻状态,你可能会希望它发出一声叹息,擦去额头的汗水。这些行为都只能是在进入或退出某个状态时出现的,而不会发生在通常的更新步骤中。因此,这个附加的函数必须理想地建立在你的switch/if-then语句中。在这个架构中你想做到这些,必定会咬牙切齿、恶心反胃,并且写出相当糟糕的代码。
3.如何使用有限状态机
整个程序的世界由BaseGameEntity继承来。它用来储存每个对象的ID号码,并且定义一个Update函数,在每个更新步骤被调用(unity3d中每个对象都自带了update函数,所以基类不需要再有)。
BaseGameEntity类声明如下:
public class BaseGameEntity : MonoBehaviour { private int m_ID;//每个对象具有一个唯一的识别数字 private static ArrayList m_idArray = new ArrayList(); public int ID () { return m_ID; } protected void SetID (int val) { //这个函数用来确认ID是否正确设置 if (m_idArray.Contains(val)) { Debug.LogError ("id cuo wu "); return; } m_idArray.Add(val); m_ID = val; } public int getID(){ return m_ID; } } |
public class People : BaseGameEntity { //指向一个状态实例的指针 StateMachine m_pStateMachine; //角色当前的位置 public location_type m_Location; //矿工角色包中装了多少金块 public int m_iGoldCarried; //矿工角色在银行存了多少钱 public int m_iMontyInBank; //矿工角色口渴程度 public int m_iThirst; //矿工角色疲劳程度 public int m_iFatigue; void Start () { // 设置ID SetID((int) People); //设置状态接口,并指向一个状态 m_pStateMachine = new StateMachine(this); m_pStateMachine.SetCurrentState(People_GloballState .Instance()); } void Update () { //调用正在使用的状态 m_pStateMachine.SMUpdate(); } public StateMachine GetFSM () { //返回状态管理机 return m_pStateMachine; } } |
先看看状态基类:
//C# 范型 public class State<entity_type> { public entity_type Target ; //进入状态 public virtual void Enter (entity_type entityType) { } //状态正常执行 public virtual void Execute (entity_type entityType) { } //退出状态 public virtual void Exit (entity_type entityType) { } } |
using UnityEngine; using System.Collections; public class StateMachine<entity_type> { //entity 实体 private entity_type m_pOwner; private State<entity_type> m_pCurrentState; private State<entity_type> m_pPreviousState; private State<entity_type> m_pGlobalState; public StateMachine (entity_type owner) { m_pOwner = owner; m_pCurrentState = null; m_pPreviousState = null; m_pGlobalState = null; } public void GlobalStateEnter() { m_pGlobalState.Enter(m_pOwner); } public void SetGlobalStateState(State<entity_type> GlobalState) { m_pGlobalState = GlobalState; m_pGlobalState.Target = m_pOwner; m_pGlobalState.Enter(m_pOwner); } public void SetCurrentState(State<entity_type> CurrentState) { m_pCurrentState = CurrentState; m_pCurrentState.Target = m_pOwner; m_pCurrentState.Enter(m_pOwner); } public void SMUpdate () { //全局状态的运行 if (m_pGlobalState != null) m_pGlobalState.Execute (m_pOwner); //一般当前状态的运行 if (m_pCurrentState != null) m_pCurrentState.Execute (m_pOwner); } public void ChangeState (State<entity_type> pNewState) { if (pNewState == null) { Debug.LogError ("该状态不存在"); } //退出之前状态 m_pCurrentState.Exit(m_pOwner); //保存之前状态 m_pPreviousState = m_pCurrentState; //设置当前状态 m_pCurrentState = pNewState; m_pCurrentState.Target = m_pOwner; //进入当前状态 m_pCurrentState.Enter (m_pOwner); } public void RevertToPreviousState () { //qie huan dao qian yi ge zhuang tai ChangeState (m_pPreviousState); } public State<entity_type> CurrentState () { //fan hui dang qian zhuang tai return m_pCurrentState; } public State<entity_type> GlobalState () { //fan hui quan ju zhuang tai return m_pGlobalState; } public State<entity_type> PreviousState () { //fan hui qian yi ge zhuang tai return m_pPreviousState; } public bool HandleMessage (Telegram msg) { //the message if (m_pCurrentState!=null && m_pCurrentState.OnMessage (m_pOwner, msg)) { return true; } // message to the global state if (m_pGlobalState!=null && m_pGlobalState.OnMessage (m_pOwner, msg)) { return true; } return false; } } |
public class People_GloballState :State<People > { private static People_GloballState instance; //Singleton设计模式,确保了一个对象只能实例化一次,它是全局可访问的。 public static People_GloballState Instance () { if (instance == null) instance = new People_GloballState (); return instance; } public override void Enter (People Entity) { //base.Enter (Entity); } public override void Execute (People Entity) { //base.Execute (Entity); } public override void Exit (People Entity) { //base.Exit (Entity); } } |
相关文章推荐
- unity 基于socket的多人群聊实现
- [新]最近用unity5弄的一些渲染
- 【Unity】12.5 Navmesh Obstacle组件
- 【Unity】12.4 通过网格分层选择行进路线
- 【Unity】12.3 Off Mesh Link组件
- 【Unity】12.2 导航网格寻路简单示例
- 【Unity】12.1 基本概念
- 【Unity】第12章 导航网格和寻路
- Unity3D研究院之IOS全自动编辑framework、plist、oc代码
- [Unity编辑器]编辑器与序列化
- Unityads安卓接入
- Unity跑酷游戏的无尽关卡是如何生成的?
- 如何在Unity中播放视频?
- Unity3d Android SDK接入解析(一)Unity3d 与 Android之间的互相调用
- 2016年Unity 大会内容记录
- 怎样查看一个Unity工程开发时所用的Unity版本
- [Unity热更新]tolua# & LuaFramework(十):扩展工具包
- Unity社交功能开发——图片上传
- Unity 8 和 Snap 将是 Ubuntu 桌面系统的未来
- unity源码解析Texture2D