Unity中状态机的使用
来源:互联网 发布:web安全工程师 知乎 编辑:程序博客网 时间:2024/06/08 09:11
Unity中状态机的使用
在游戏中,人物的状态是不断变化的,所以写个FSM来管理状态是必要的。
一个有限状态机是一个设备,或者是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使得一个状态变换到另一个状态,或者是使一个输入或者一种行为的发生。一个有限状态机在任何瞬间只能处在一种状态。
设置状态的常量
我们这里设置了几个普通的idle,run,death的常量
public class ConstStrings{ //状态 常量 public const string St_Born = "born";//出生 public const string St_Idle = "idle";//静止 public const string St_FunnyIdle = "funnyidle";//休闲动作 public const string St_Run = "run";//移动 public const string St_Dead = "death";//死亡 public const string St_Relive = "relive";//复活 public const string St_Jump = "jump";//跳跃}
定义状态图
/// <summary>/// 状态图,存储角色可以切换的所有状态/// </summary>public class CharStateGraph{ /// <summary> /// 状态图的名称 /// </summary> public string StateGraphName; /// <summary> /// 存储角色所有的状态 /// </summary> public Dictionary<string, CharSateBase> states = new Dictionary<string, CharSateBase>(); /// <summary> /// 仅用作当前状态的定时器 /// 切换状态时清空 /// </summary> public uint[] framtimers; public uint[] timers; public CharStateGraph() { framtimers = new uint[10]; timers = new uint[10]; } ~CharStateGraph() { StopTimers(); framtimers = null; timers = null; }
下面来定义一般的状态图,继承于上面的状态图。
/// <summary>/// 一般状态图/// </summary>public class SGCommon : CharStateGraph{ public SGCommon() { CommonStates.AddBorn(states); CommonStates.AddIdle(states); CommonStates.AddFunnyIdle(states); CommonStates.AddAttack(states); CommonStates.AddMoveAttack(states); CommonStates.AddRun(states); CommonStates.AddDeath(states); }}
状态的切换
在状态图里面,常需要的就是切换状态的行为,改变人物的状态。
这个了类是用来管理状态机的,就是在实际应用时候去调用的了。
/// <summary>/// 状态图实例,用于实现状态切换等功能/// </summary>public class StateGraphInstance{ /// <summary> /// 状态图 /// </summary> public CharStateGraph sg; /// <summary> /// 当前状态 /// </summary> public CharSateBase currentState; /// <summary> /// 前一个状态 /// </summary> public CharSateBase preState; /// <summary> /// 角色实体 /// </summary> public BaseController inst; public Delegate OnStop; public Delegate OnStart; public StateGraphInstance(CharStateGraph sg, BaseController inst) { this.sg = sg; this.inst = inst; } ~StateGraphInstance() { sg = null; currentState = null; preState = null; OnStop = null; OnStart = null; inst = null; } public void Start() { if (OnStart != null) OnStart.DynamicInvoke(); } public void Update() { if (currentState != null) { currentState.Update(inst, Time.time); } } public void Stop() { sg.StopTimers(); sg = null; if (OnStop != null) OnStop.DynamicInvoke(); currentState = null; preState = null; inst = null; OnStop = null; OnStart = null; } /// <summary> /// 进入状态 /// </summary> /// <param name="statename"></param> /// <param name="objs"></param> public void GoToState(string statename, params object[] objs) { CharSateBase state; if (sg.states.TryGetValue(statename, out state)) { preState = currentState; if (preState != null) preState.ClearAddTags(); if (currentState != null && currentState.onexit != null) { currentState.Exit(inst, objs); } sg.StopTimers(); currentState = state; currentState.Enter(inst, objs); } }
角色的状态
另外还定义了角色的状态,角色状态的名字,角色的状态的进入和退出。
其实这里的 CharStateGraph就是状态机,里面保存状态图的简单信息,名字,停止时间等。
CharStateBase就是普通的状态。
在状态图里面,我们使用来管理状态图的。相当于这个就是一个状态机,状态机和状态的关系是一对多的关系。
在CharStateBase里面有三个常用的状态的改变,状态进入Enter,更新Update,退出Exit。
/// <summary>/// 角色状态/// </summary>public class CharSateBase{ /// <summary> /// 状态名字 /// </summary> public string statename; /// <summary> /// 状态开始的时间 /// </summary> private float starttime; /// <summary> /// 状态的标签 /// </summary> // busy 表示上层是否可以操控 // atomic 表示状态之间是否不被打断 // canrotate // norotate // canmove // nomove public HashSet<string> tags; /// <summary> /// 状态额外加的标签 /// </summary> public HashSet<string> addTags; /// <summary> /// 状态进入是的委托 /// </summary> public Delegate onenter; /// <summary> /// 状态退出的委托 /// </summary> public Delegate onexit; /// <summary> /// 状态更新的事件 /// </summary> public Action<BaseController, float> onupdate; /// <summary> /// 状态中监听的事件 /// </summary> /// <summary> /// 进入状态 /// </summary> public void Enter(BaseController bc, params object[] objs) { starttime = Time.time; if (onenter != null) { onenter.DynamicInvoke(bc, objs); } } public void Update(BaseController bc,float curtime) { if (onupdate != null) { onupdate.DynamicInvoke(bc, curtime - starttime); } } /// <summary> /// 退出状态 /// </summary> public void Exit(BaseController bc,params object[] objs) { if (onexit != null) { onexit.DynamicInvoke(bc,objs); } }
其实上面的是状态机的名字的改变,实质上还是普通的状态机,下面看下常见的状态机模式。
常见的状态机模式
Istate
Istate是状态机的抽象基类。以后的很多的状态就可以去继承这个基类的。
public abstract class IState<T,F>{ public T Owner { get; set; } public F Fsm { get; set; } public IStateParam baseparam { get; private set; } public void SetParam(IStateParam _param) { baseparam = _param; } public void SetFSMID(F id) { Fsm = id; } public abstract bool CheckTransition(); public abstract void Enter(); public abstract void Execute(); public abstract void Exit();}
我们现在使用的是来管理摄像机的一些状态,下面只去列举一种摄像机的状态,实际上有很多种的。如若不是,实现状态机的意义也就是没有的了。
// 相机展示时装直接跟随public class CamFashionShowFollowState : IState<FreeLookCam,FSMState>{ public CamFashionShowFollowParam mDirparam; public override bool CheckTransition() { return true; } public override void Enter() {#if UNITY_EDITOR Debug.Log("CamFashionShowFollowState " + Time.time);#endif mDirparam = baseparam as CamFashionShowFollowParam; FreeLookCam.Instance.CanZoom = false; FreeLookCam.Instance.CanRotate = true; } public override void Execute() { if (FreeLookCam.Instance != null) FreeLookCam.Instance.DirFollowTarget(); } public override void Exit() { }}
状态机IstateMachine类
public class IStateMachine<T, F>{ private T Owner { get; set; } private Dictionary<F, IState<T, F>> mStates; private IState<T, F> mCurrState; private IState<T, F> mPrevState; private IState<T, F> mGlobalState; public IStateMachine(T owner) { this.Owner = owner; mStates = new Dictionary<F, IState<T, F>>(); } public bool Contains(F fsmID) { return this.mStates.ContainsKey(fsmID); } public void AddState(F fsmID, IState<T, F> state) { if (Contains(fsmID)) { return; } state.SetFSMID(fsmID); state.Owner = Owner; mStates.Add(fsmID, state); } public IState<T, F> GetState(F fsmID) { if (Contains(fsmID)) { return mStates[fsmID]; } return null; } public void ChangeState(IState<T, F> newState) { mPrevState = mCurrState; mCurrState.Exit(); mCurrState = newState; mCurrState.Enter(); } public void ChangeState(F newFSM) { IState<T, F> newState = GetState(newFSM); if (newState != null) { ChangeState(newState); } } public void SetCurrState(IState<T, F> fsm) { mCurrState = fsm; } public IState<T, F> GetCurState() { return mCurrState; } public F GetCurrStateID() { if (mCurrState == null) { return default(F); } return mCurrState.Fsm; } public void Start() { if (mCurrState != null) { mCurrState.Enter(); } if (mGlobalState != null) { mGlobalState.Enter(); } }}
这里就是差不多就要完成的了,上文还有一个实例化状态机的类StateGraphInstance,这是用来管理状态机的,在这里就不如列举了。
阅读全文
0 0
- Unity中状态机的使用
- Unity动画,状态机的使用
- Unity中状态机模式的简单封装
- unity怪物的状态机
- Unity中实现一个状态机
- 状态机中使用事件优先级的探讨
- 状态机中使用事件优先级的探讨
- unity3d中使用状态机
- unity状态机
- QT状态机的使用
- 状态机的使用场合
- [Unity基础]一个简单的状态机
- Unity 下简易状态机的实现
- 让你轻松学会unity的状态机?
- 字符串中单词的个数(状态机的使用)
- 字符串中单词的个数(状态机的使用)
- 字符串中单词的个数(状态机的使用)
- verilog中状态机的写法
- Ubuntu的启动栏:左边还是下边
- 非旋转treap模板
- [noip2009]: 最优贸易
- 原生JS实现选项卡效果实例
- waitpid函数的使用
- Unity中状态机的使用
- php-11
- harbor 高可用部署
- AE--属性表添加字段,修改字段属性
- 在看一个$injector用法的demo,下面是demo的所有代码:
- Spring框架的主要功能
- elasticsearch源码分析之启动过程
- 质量压缩与二级采样
- BZOJ 1211: [HNOI2004]树的计数 prufer编码