我是靠谱客的博主 包容黄蜂,最近开发中收集的这篇文章主要介绍Unity中状态机的使用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中状态机的使用Unity中状态机的使用常见的状态机模式的全部内容,希望文章能够帮你解决Unity中状态机的使用Unity中状态机的使用常见的状态机模式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(83)

评论列表共有 0 条评论

立即
投稿
返回
顶部