Unity中状态机的使用
Posted xiaogeformax
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity中状态机的使用相关的知识,希望对你有一定的参考价值。
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,这是用来管理状态机的,在这里就不如列举了。
以上是关于Unity中状态机的使用的主要内容,如果未能解决你的问题,请参考以下文章