C# Unity FSM 状态机

这篇具有很好参考价值的文章主要介绍了C# Unity FSM 状态机。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C# Unity FSM 状态机

使用状态机可以降低代码耦合性,并且可以优化代码可读性,方便团队协作等。
对于游戏开发内容来讲游戏开发的流程控制玩家动画都可以使用FSM有限状态机来实现。

1.FsmState

每个状态的基类,泛型参数表示所拥有者

public abstract class FsmState<T> where T : class
{
    protected internal abstract void OnInit(IFsm<T> fsm);
    protected internal abstract void OnEnter(IFsm<T> fsm);
    protected internal abstract void OnUpdate(IFsm<T> fsm);
    protected internal abstract void OnLeave(IFsm<T> fsm);
    protected internal abstract void OnDestroy(IFsm<T> fsm);

    protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>
    {
        Fsm<T> fsmImplement = (Fsm<T>)fsm;
        if(fsmImplement == null)
        {
            throw new Exception("FSM is invalid.");
        }
        fsmImplement.ChangeState<TState>();
    }
    protected void ChangeState(IFsm<T> fsm, Type stateType)
    {
        Fsm<T> fsmImplement = (Fsm<T>)fsm;
        if (fsmImplement == null)
        {
            throw new Exception("FSM is invalid.");
        }

        if (stateType == null)
        {
            throw new Exception("State type is invalid.");
        }

        if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
        {
            throw new Exception("State type is invalid.");
        }

        fsmImplement.ChangeState(stateType);
    }
}

2.IFsm

有限状态机的接口

public interface IFsm<T> where T : class
{
    string Name
    {
        get;
    }
    string FullName
    {
        get;
    }
    T Owner
    {
        get;
    }
    int FsmStateCount
    {
        get;
    }
    bool IsRunning
    {
        get;
    }
    bool IsDestroyed
    {
        get;
    }
    FsmState<T> CurrentState
    {
        get;
    }
    float CurrentStateTime
    {
        get;
    }

    void Start<TState>() where TState : FsmState<T>;
    bool HasState<TState>() where TState : FsmState<T>;
    TState GetState<TState>() where TState : FsmState<T>;
    FsmState<T> GetState(Type stateType);
    FsmState<T>[] GetAllStates();
}

3.IFsmManager

有限状态机管理器接口

public interface IFsmManager
{
    int Count { get; }
    bool HasFsm<T>() where T : class;
    bool HasFsm(Type ownerType);
    bool HasFsm<T>(string name) where T : class;
    bool HasFsm(Type ownerType, string name);

    IFsm<T> GetFsm<T>() where T : class;
    IFsm<T> GetFsm<T>(string name) where T : class;

    IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] fsmStates) where T : class;
    IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class;
    IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class;
    IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class;

    bool DestroyFsm<T>() where T : class;
    bool DestroyFsm(Type ownerType);
    bool DestroyFsm<T>(string name) where T : class;
    bool DestroyFsm(Type ownerType, string name);
    bool DestroyFsm<T>(IFsm<T> fsm) where T : class;
}

4.FsmBase

有限状态机的基类

public abstract class FsmBase
{
    private string m_Name;

    public FsmBase()
    {
        m_Name = string.Empty;
    }

    public string Name
    {
        get
        {
            return m_Name;
        }
        protected set
        {
            m_Name = value ?? string.Empty;
        }
    }

    public string FullName
    {
        get
        {
            return $"{OwnerType.FullName}.{Name}";
        }
    }

    public abstract Type OwnerType
    {
        get;
    }

    public abstract int FsmStateCount
    {
        get;
    }

    public abstract bool IsRunning
    {
        get;
    }

    public abstract bool IsDestroyed
    {
        get;
    }

    public abstract string CurrentStateName
    {
        get;
    }

    public abstract float CurrentStateTime
    {
        get;
    }

    public abstract void Update();
    public abstract void Shutdown();
}

5.Fsm

状态机类

public class Fsm<T> : FsmBase, IFsm<T> where T : class
{
    private T m_Owner;
    private readonly Dictionary<Type, FsmState<T>> m_States;
    private FsmState<T> m_CurrentState;
    private float m_CurrentStateTime;
    private bool m_IsDestroyed;
    public Fsm()
    {
        m_Owner = null;
        m_States = new Dictionary<Type, FsmState<T>>();
        m_CurrentState = null;
        m_CurrentStateTime = 0f;
        m_IsDestroyed = true;
    }
    public T Owner => m_Owner;
    public FsmState<T> CurrentState => m_CurrentState;
    public override Type OwnerType => typeof(T);
    public override int FsmStateCount => m_States.Count;
    public override bool IsRunning => m_CurrentState != null;
    public override bool IsDestroyed => m_IsDestroyed;
    public override string CurrentStateName => m_CurrentState != null ? m_CurrentState.GetType().FullName : null;
    public override float CurrentStateTime => m_CurrentStateTime;
    public static Fsm<T> Create(string name,T owner,params FsmState<T>[] states)
    {
        if(owner == null)
        {
            throw new Exception("FSM owner is invalid.");
        }
        if(states== null|| states.Length < 1)
        {
            throw new Exception("FSM states is invalid.");
        }

        Fsm<T> fsm = Pool<Fsm<T>>.Rent();
        fsm.Name = name;
        fsm.m_Owner = owner;
        fsm.m_IsDestroyed = false;
        foreach (FsmState<T> oneState in states)
        {
            if(oneState == null)
            {
                throw new Exception("FSM states is invalid.");
            }

            Type stateType = oneState.GetType();
            if (fsm.m_States.ContainsKey(stateType))
            {
                throw new Exception($"{stateType} state is already exist");
            }
            fsm.m_States.Add(stateType, oneState);
            oneState.OnInit(fsm);
        }
        return fsm;
    }
    public static Fsm<T> Create(string name,T owner,List<FsmState<T>> states)
    {
        if (owner == null)
        {
            throw new Exception("FSM owner is invalid.");
        }
        if (states == null || states.Count < 1)
        {
            throw new Exception("FSM states is invalid.");
        }

        Fsm<T> fsm = Pool<Fsm<T>>.Rent();
        fsm.Name = name;
        fsm.m_Owner = owner;
        fsm.m_IsDestroyed = false;
        foreach (FsmState<T> oneState in states)
        {
            if (oneState == null)
            {
                throw new Exception("FSM states is invalid.");
            }

            Type stateType = oneState.GetType();
            if (fsm.m_States.ContainsKey(stateType))
            {
                throw new Exception($"{stateType} state is already exist");
            }
            fsm.m_States.Add(stateType, oneState);
            oneState.OnInit(fsm);
        }
        return fsm;
    }
    public FsmState<T>[] GetAllStates()
    {
        int index = 0;
        FsmState<T>[] arr = new FsmState<T>[m_States.Count];
        foreach (FsmState<T> fsmState in m_States.Values)
        {
            arr[index++] = fsmState;
        }
        return arr;
    }
    public bool HasState<TState>() where TState : FsmState<T>
    {
        return m_States.ContainsKey(typeof(TState));
    }
    public override void Shutdown()
    {
        Pool<Fsm<T>>.Return(this, (fsm) =>
         {
             if(m_CurrentState != null)
             {
                 m_CurrentState.OnLeave(this);
             }
             foreach (FsmState<T> oneState in m_States.Values)
             {
                 oneState.OnDestroy(this);
             }

             Name = null;
             m_Owner = null;
             m_States.Clear();



             m_CurrentState = null;
             m_CurrentStateTime = 0f;
             m_IsDestroyed = true;
         });
    }
    public void Start<TState>() where TState : FsmState<T>
    {
        if (IsRunning)
        {
            throw new Exception("FSM is running, can not start again.");
        }
        FsmState<T> state = GetState<TState>();
        if (state == null)
        {
            throw new Exception("can not start state");
        }
        m_CurrentStateTime = 0f;
        m_CurrentState = state;
        m_CurrentState.OnEnter(this);
    }
    public void Start(Type stateType)
    {
        if (IsRunning)
        {
            throw new Exception("FSM is running, can not start again.");
        }

        if (stateType == null)
        {
            throw new Exception("State type is invalid.");
        }

        if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
        {
            throw new Exception("State type is invalid.");
        }

        FsmState<T> state = GetState(stateType);
        if (state == null)
        {
            throw new Exception("FSM can not start state which is not exist.");
        }

        m_CurrentStateTime = 0f;
        m_CurrentState = state;
        m_CurrentState.OnEnter(this);
    }
    public override void Update()
    {
        m_CurrentStateTime += Time.deltaTime;
        m_CurrentState.OnUpdate(this);
    }
    public TState GetState<TState>() where TState : FsmState<T>
    {
        if (m_States.TryGetValue(typeof(TState), out FsmState<T> fsmState))
        {
            return (TState)fsmState;
        }
        return null;
    }
    public FsmState<T> GetState(Type stateType)
    {
        if (stateType == null)
        {
            throw new Exception("State type is invalid.");
        }

        if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
        {
            throw new Exception("State type is invalid.");
        }

        if (m_States.TryGetValue(stateType, out FsmState<T> fsmState))
        {
            return fsmState;
        }
        return null;
    }
    public void ChangeState<TState>()
    {
        ChangeState(typeof(TState));
    }
    public void ChangeState(Type stateType)
    {
        if (m_CurrentState == null)
        {
            throw new Exception("Current state is invalid.");
        }

        FsmState<T> state = GetState(stateType);
        if (state == null)
        {
            throw new Exception("FSM can not change state which is not exist.");
        }

        m_CurrentState.OnLeave(this);
        m_CurrentStateTime = 0f;
        m_CurrentState = state;
        m_CurrentState.OnEnter(this);
    }
}

6.FsmManager

状态机管理器文章来源地址https://www.toymoban.com/news/detail-702778.html

public class FsmManager : Singleton<FsmManager>,IFsmManager,IUpdateSingleton
{
    private readonly Dictionary<string, FsmBase> m_FsmDic;
    private readonly List<FsmBase> m_TempFsms;
    public FsmManager()
    {
        m_FsmDic = new Dictionary<string, FsmBase>();
        m_TempFsms = new List<FsmBase>();
    }
    public int Count => m_FsmDic.Count;

    public IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] fsmStates) where T : class
    {
        return CreateFsm(string.Empty, owner, fsmStates);
    }
    public IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class
    {
        if (HasFsm<T>(name))
        {
            throw new Exception("Already exist FSM");
        }
        Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
        m_FsmDic.Add(fsm.FullName, fsm);
        return fsm;
    }
    public IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class
    {
        return CreateFsm(string.Empty, owner, states);
    }
    public IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class
    {
        if (HasFsm<T>(name))
        {
            throw new Exception("Already exist FSM");
        }
        Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
        m_FsmDic.Add(fsm.FullName, fsm);
        return fsm;
    }

    public bool DestroyFsm<T>() where T : class
    {
        return InternalDestroyFsm($"{typeof(T).FullName}.{string.Empty}");
    }
    public bool DestroyFsm(Type ownerType)
    {
        if (ownerType == null)
        {
            throw new Exception("Owner type is invalid.");
        }
        return InternalDestroyFsm($"{ownerType.FullName}.{string.Empty}");
    }
    public bool DestroyFsm<T>(string name) where T : class
    {
        return InternalDestroyFsm($"{typeof(T).FullName}.{name}");
    }
    public bool DestroyFsm(Type ownerType, string name)
    {
        if (ownerType == null)
        {
            throw new Exception("Owner type is invalid.");
        }
        return InternalDestroyFsm($"{ownerType.FullName}.{name}");
    }
    public bool DestroyFsm<T>(IFsm<T> fsm) where T : class
    {
        if (fsm == null)
        {
            throw new Exception("FSM is invalid.");
        }
        return InternalDestroyFsm(fsm.FullName);
    }

    public IFsm<T> GetFsm<T>() where T : class
    {
        return (IFsm<T>)InternalGetFsm($"{typeof(T).FullName}.{string.Empty}");
    }
    public IFsm<T> GetFsm<T>(string name) where T : class
    {
        return (IFsm<T>)InternalGetFsm($"{typeof(T).FullName}.{name}");
    }

    public bool HasFsm<T>() where T : class
    {
        return InternalHasFsm($"{typeof(T).FullName}.{string.Empty}");
    }
    public bool HasFsm(Type ownerType)
    {
        if(ownerType == null)
        {
            throw new Exception("Owner type is invalid.");
        }
        return InternalHasFsm($"{ownerType.FullName}.{string.Empty}");
    }
    public bool HasFsm<T>(string name) where T : class
    {
        return InternalHasFsm($"{typeof(T).FullName}.{name}");
    }
    public bool HasFsm(Type ownerType, string name)
    {
        if (ownerType == null)
        {
            throw new Exception("Owner type is invalid.");
        }
        return InternalHasFsm($"{ownerType.FullName}.{name}");
    }


    private bool InternalDestroyFsm(string name)
    {
        if(m_FsmDic.TryGetValue(name,out FsmBase fsmBase))
        {
            fsmBase.Shutdown();
            return m_FsmDic.Remove(name);
        }
        return false;
    }
    private FsmBase InternalGetFsm(string name)
    {
        FsmBase fsm = null;
        if (m_FsmDic.TryGetValue(name, out fsm))
        {
            return fsm;
        }

        return null;
    }
    private bool InternalHasFsm(string name)
    {
        return m_FsmDic.ContainsKey(name);
    }

    public void Update()
    {
        m_TempFsms.Clear();
        if (m_FsmDic.Count <= 0)
            return;


        foreach (FsmBase fsmBase in m_FsmDic.Values)
        {
            m_TempFsms.Add(fsmBase);
        }

        foreach (FsmBase fsmBase in m_TempFsms)
        {
            if (fsmBase.IsDestroyed)
                continue;
            fsmBase.Update();
        }
    }

    protected override void Load(int assemblyName)
    {
        
    }

    protected override void UnLoad(int assemblyName)
    {
        
    }
}

7.测试

(一)IdleState

public class IdleState : FsmState<FsmTest>
{
    protected internal override void OnDestroy(IFsm<FsmTest> fsm)
    {
        Debug.Log("销毁 IdleState");
    }

    protected internal override void OnEnter(IFsm<FsmTest> fsm)
    {
        Debug.Log("进入 IdleState");
    }

    protected internal override void OnInit(IFsm<FsmTest> fsm)
    {
    }

    protected internal override void OnLeave(IFsm<FsmTest> fsm)
    {
        Debug.Log("离开 IdleState");
    }

    protected internal override void OnUpdate(IFsm<FsmTest> fsm)
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            ChangeState<WalkState>(fsm);
        }
    }
}

(二)WalkState

public class WalkState : FsmState<FsmTest>
{
    protected internal override void OnDestroy(IFsm<FsmTest> fsm)
    {
        Debug.Log("销毁 WalkState");
    }

    protected internal override void OnEnter(IFsm<FsmTest> fsm)
    {
        Debug.Log("进入 WalkState");
    }

    protected internal override void OnInit(IFsm<FsmTest> fsm)
    {
    }

    protected internal override void OnLeave(IFsm<FsmTest> fsm)
    {
        Debug.Log("离开 WalkState");
    }

    protected internal override void OnUpdate(IFsm<FsmTest> fsm)
    {
        if (Input.GetKeyDown(KeyCode.B))
        {
            ChangeState<RunState>(fsm);
        }
    }
}

(三)RunState

public class RunState : FsmState<FsmTest>
{
    protected internal override void OnDestroy(IFsm<FsmTest> fsm)
    {
        Debug.Log("销毁 RunState");
    }

    protected internal override void OnEnter(IFsm<FsmTest> fsm)
    {
        Debug.Log("进入 RunState");
    }

    protected internal override void OnInit(IFsm<FsmTest> fsm)
    {
    }

    protected internal override void OnLeave(IFsm<FsmTest> fsm)
    {
        Debug.Log("离开 RunState");
    }

    protected internal override void OnUpdate(IFsm<FsmTest> fsm)
    {
        if (Input.GetKeyDown(KeyCode.C))
        {
            ChangeState<IdleState>(fsm);
        }
    }
}

mono测试

public class FsmTest : MonoBehaviour
{
    private IFsm<FsmTest> m_TestFsm;
    void Start()
    {
        SingletonSystem.Initialize();
        AssemblyManager.Load(1, GetType().Assembly);

        m_TestFsm = FsmManager.Instance.CreateFsm<FsmTest>("MyTestFsm",this, new IdleState(),new WalkState(),new RunState());
        m_TestFsm.Start<IdleState>();
    }

    void Update()
    {
        SingletonSystem.Update();
        if (Input.GetKeyDown(KeyCode.P))
        {
            FsmManager.Instance.DestroyFsm(m_TestFsm);
        }
    }
}

到了这里,关于C# Unity FSM 状态机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring状态机(FSM),让订单状态流转如丝般顺滑

    在复杂的应用程序设计中,尤其是那些涉及多个状态变迁和业务流程控制的场景,有限状态机( Finite State Machine, FSM )是一种强大而有效的建模工具。Spring框架为此提供了Spring状态机( Spring State Machine )这一组件,它允许开发者以一种声明式且结构清晰的方式来管理和控制对

    2024年03月12日
    浏览(51)
  • Go中的有限状态机FSM的详细介绍

    1.1 有限状态机的定义 有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分: 状态(State)、事件(Event)、动作(Action) ,事件(转移条件)触发状态的转移和动作的执行。动作的执行不是必须的,可

    2023年04月24日
    浏览(34)
  • 如何基于FSM有限状态机实现Enemies AI

    本文简单介绍如何基于FSM有限状态机实现Enemies AI,首先定义敌人的AI逻辑:默认状态下Enemy为巡逻状态,有若干巡逻点位,Enemy在这些点位之间来回巡逻走动,同时检测Player的位置,当Player进入一定范围内时,Enemy进入寻路状态,寻路到Player位置前,进入Attacking攻击状态,当

    2023年04月09日
    浏览(39)
  • Go中的有限状态机FSM的详细介绍 _

    1、FSM简介 1.1 有限状态机的定义 有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分: 状态(State)、事件(Event)、动作(Action) ,事件(转移条件)触发状态的转移和动作的执行。动作的执行不是必

    2024年02月12日
    浏览(69)
  • Unity有限状态机

    一、引言 在游戏开发中,经常会遇到游戏角色或实体具有多种状态,并且在不同状态之间需要切换的情况。例如,一个角色可能处于行走、奔跑、跳跃等不同的状态,并且根据玩家的输入或游戏逻辑,在这些状态之间进行切换。为了管理这些状态及其之间的转换,我们可以使

    2024年02月03日
    浏览(51)
  • unity动画状态机

    动画状态机(Animation State Machine)是Unity中用于控制动画状态转换的工具,它由多个状态(State)和转换(Transition)组成,可以通过状态转换来控制动画的播放行为。 在动画状态机中,每个状态都代表了一个动画片段(Animation Clip),可以设置动画片段的播放速度、循环模式、

    2024年02月07日
    浏览(56)
  • Unity实现设计模式——状态模式

    状态模式最核心的设计思路就是将对象的状态抽象出一个接口,然后根据它的不同状态封装其行为,这样就可以实现状态和行为的绑定,最终实现对象和状态的有效解耦。 在实际开发中一般用到FSM有限状态机的实现,GF框架中的FSM和流程控制就是基于这个原理实现的。 状态

    2024年02月08日
    浏览(34)
  • 在Unity中实现有限状态机

    本文将介绍Unity开发中的有限状态机,给出对应的实现代码。 有限状态机借鉴了图灵机的思想,可以看作是最简单的图灵机。 它包含4要素: 现态 条件 动作 次态 基础的有限状态机不复杂,无非是几个状态定义成类,提供OnEnter/OnExit/OnUpdate方法,这里直接根据需求给出对应的

    2024年02月05日
    浏览(50)
  • 【Unity】Unity C#基础(十四)注释

    /// 是智能注释也称xml注释,会在被编译,并生成xml文件在可执行文件中。会影响编译速度,但不会影响代码执行速度。 一级注释 二级注释 另外,还可以自定义 XML 标签 。 注释换行 在 C# 智能注释时,常常希望它能在开发时显示为换行,使得提示更加友好!原来一直想怎么实

    2024年02月03日
    浏览(32)
  • unity中如何查看网络是否可用状态

    目录 一、检查网络是否可用及类型 二、如何获得网络信号的强弱: 1、Android检查网络信号强弱 2、在IOS设备下获得网络信号的强弱 在 Unity 中,可以使用  Application.internetReachability  属性来检查网络是否可用。 Application.internetReachability  返回一个枚举值,表示当前设备的网络

    2024年02月09日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包