您当前的位置: 首页 >  unity

CoderZ1010

暂无认证

  • 4浏览

    0关注

    168博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity【设计模式】- 构建FSM有限状态机

CoderZ1010 发布时间:2022-01-10 15:31:25 ,浏览量:4

FSM(Finite State Machine)有限状态机,广泛应用于状态类、流程类、步骤类程序的处理。

1. 定义状态接口、抽象状态类,状态包含的五个基本行为:

        · OnInitialization 状态初始化事件

        · OnEnter 状态进入事件

        · OnStay 状态停留事件

        · OnExit 状态退出事件

        · OnTermination 状态终止事件

using System;

namespace SK.Framework
{
    /// 
    /// 状态接口
    /// 
    public interface IState 
    {
        /// 
        /// 状态名称
        /// 
        string Name { get; set; }
        /// 
        /// 状态初始化事件
        /// 
        void OnInitialization();
        /// 
        /// 状态进入事件
        /// 
        void OnEnter();
        /// 
        /// 状态停留事件(Update)
        /// 
        void OnStay();
        /// 
        /// 状态退出事件
        /// 
        void OnExit();
        /// 
        /// 状态终止事件
        /// 
        void OnTermination();
        /// 
        /// 状态切换条件
        /// 
        /// 切换条件
        /// 目标状态名称
        void SwitchWhen(Func predicate, string targetStateName);
    }
}
using System;

namespace SK.Framework
{
    /// 
    /// 抽象状态类
    /// 
    public class State : IState
    {
        /// 
        /// 状态名称
        /// 
        public string Name { get; set; }
        /// 
        /// 所属状态机
        /// 
        public StateMachine machine;
        /// 
        /// 状态初始化事件
        /// 
        public Action onInitialization;
        /// 
        /// 状态进入事件
        /// 
        public Action onEnter;
        /// 
        /// 状态停留事件
        /// 
        public Action onStay;
        /// 
        /// 状态退出事件
        /// 
        public Action onExit;
        /// 
        /// 状态终止事件
        /// 
        public Action onTermination;

        /// 
        /// 状态初始化事件
        /// 
        public virtual void OnInitialization()
        {
            onInitialization?.Invoke();
        }
        /// 
        /// 状态进入事件
        /// 
        public virtual void OnEnter()
        {
            onEnter?.Invoke();
        }
        /// 
        /// 状态停留事件
        /// 
        public virtual void OnStay()
        {
            onStay?.Invoke();
        }
        /// 
        /// 状态退出事件
        /// 
        public virtual void OnExit()
        {
            onExit?.Invoke();
        }
        /// 
        /// 状态终止事件
        /// 
        public virtual void OnTermination()
        {
            onTermination?.Invoke();
        }
        /// 
        /// 设置状态切换条件
        /// 
        /// 切换条件
        /// 目标状态名称
        public void SwitchWhen(Func predicate, string targetStateName)
        {
            machine.SwitchWhen(predicate, Name, targetStateName);
        }
    }
}

SwitchWhen函数用于为该状态切换到其他指定状态添加切换条件,当条件满足时,状态机会自动切换到目标状态。

2. 定义状态机类,状态机包含的基本行为:

        · Add 添加状态

        · Remove 移除状态

        · Switch 切换状态

using System;
using UnityEngine;
using System.Collections.Generic;

namespace SK.Framework
{
    /// 
    /// 状态机
    /// 
    public class StateMachine
    {
        //状态列表 存储状态机内所有状态
        protected readonly List states = new List();
        //状态切换条件列表
        protected List conditions = new List();
        
        /// 
        /// 状态机名称
        /// 
        public string Name { get; set; }
        /// 
        /// 当前状态
        /// 
        public IState CurrentState { get; protected set; }

        /// 
        /// 添加状态
        /// 
        /// 状态
        /// 添加成功返回true 否则返回false
        public bool Add(IState state)
        {
            //判断是否已经存在
            if (!states.Contains(state))
            {
                //判断是否存在同名状态
                if (states.Find(m => m.Name == state.Name) == null)
                {
                    //存储到列表
                    states.Add(state);
                    //执行状态初始化事件
                    state.OnInitialization();
                    return true;
                }
            }
            return false;
        }
        /// 
        /// 添加状态
        /// 
        /// 状态类型
        /// 状态命名
        /// 添加成功返回true 否则返回false
        public bool Add(string stateName = null) where T : IState, new()
        {
            Type type = typeof(T);
            T t = (T)Activator.CreateInstance(type);
            t.Name = string.IsNullOrEmpty(stateName) ? type.Name : stateName;
            return Add(t);
        }
        /// 
        /// 移除状态
        /// 
        /// 状态
        /// 移除成功返回true 否则返回false
        public bool Remove(IState state)
        {
            //判断是否存在
            if (states.Contains(state))
            {
                //如果要移除的状态为当前状态 首先执行当前状态退出事件
                if (CurrentState == state)
                {
                    CurrentState.OnExit();
                    CurrentState = null;
                }
                //执行状态终止事件
                state.OnTermination();
                return states.Remove(state);
            }
            return false;
        }
        /// 
        /// 移除状态
        /// 
        /// 状态名称
        /// 移除成功返回true 否则返回false
        public bool Remove(string stateName)
        {
            var targetIndex = states.FindIndex(m => m.Name == stateName);
            if (targetIndex != -1)
            {
                var targetState = states[targetIndex];
                if (CurrentState == targetState)
                {
                    CurrentState.OnExit();
                    CurrentState = null;
                }
                targetState.OnTermination();
                return states.Remove(targetState);
            }
            return false;
        }
        /// 
        /// 移除状态
        /// 
        /// 状态类型
        /// 移除成返回true 否则返回false
        public bool Remove() where T : IState
        {
            return Remove(typeof(T).Name);
        }
        /// 
        /// 切换状态
        /// 
        /// 状态
        /// 切换成功返回true 否则返回false
        public bool Switch(IState state)
        {
            //如果当前状态已经是切换的目标状态 无需切换 返回false
            if (CurrentState == state) return false;
            //当前状态不为空则执行状态退出事件
            CurrentState?.OnExit();
            //判断切换的目标状态是否存在于列表中
            if (!states.Contains(state)) return false;
            //更新当前状态
            CurrentState = state;
            //更新后 当前状态不为空则执行状态进入事件
            CurrentState?.OnEnter();
            return true;
        }
        /// 
        /// 切换状态
        /// 
        /// 状态名称
        /// 切换成功返回true 否则返回false
        public bool Switch(string stateName)
        {
            //根据状态名称在列表中查询
            var targetState = states.Find(m => m.Name == stateName);
            return Switch(targetState);
        }
        /// 
        /// 切换状态
        /// 
        /// 状态类型
        /// 切换成返回true 否则返回false
        public bool Switch() where T : IState
        {
            return Switch(typeof(T).Name);
        }
        /// 
        /// 切换至下一状态
        /// 
        public void Switch2Next()
        {
            if (states.Count != 0)
            {
                //如果当前状态不为空 则根据当前状态找到下一个状态
                if (CurrentState != null)
                {
                    int index = states.IndexOf(CurrentState);
                    //当前状态的索引值+1后若小于列表中的数量 则下一状态的索引为index+1
                    //否则表示当前状态已经是列表中的最后一个 下一状态则回到列表中的第一个状态 索引为0
                    index = index + 1 < states.Count ? index + 1 : 0;
                    IState targetState = states[index];
                    //首先执行当前状态的退出事件 再更新到下一状态
                    CurrentState.OnExit();
                    CurrentState = targetState;
                }
                //当前状态为空 则直接进入列表中的第一个状态
                else
                {
                    CurrentState = states[0];
                }
                //执行状态进入事件
                CurrentState.OnEnter();
            }
        }
        /// 
        /// 切换至上一状态
        /// 
        public void Switch2Last()
        {
            if (states.Count != 0)
            {
                //如果当前状态不为空 则根据当前状态找到上一个状态
                if (CurrentState != null)
                {
                    int index = states.IndexOf(CurrentState);
                    //当前状态的索引值-1后若大等于0 则下一状态的索引为index-1
                    //否则表示当前状态是列表中的第一个 上一状态则回到列表中的最后一个状态
                    index = index - 1 >= 0 ? index - 1 : states.Count - 1;
                    IState targetState = states[index];
                    //首先执行当前状态的退出事件 再更新到上一状态
                    CurrentState.OnExit();
                    CurrentState = targetState;
                }
                //当前状态为空 则直接进入列表中的最后一个状态
                else
                {
                    CurrentState = states[states.Count - 1];
                }
                //执行状态进入事件
                CurrentState.OnEnter();
            }
        }
        /// 
        /// 切换至空状态(退出当前状态)
        /// 
        public void Switch2Null()
        {
            if (CurrentState != null)
            {
                CurrentState.OnExit();
                CurrentState = null;
            }
        }
        /// 
        /// 获取状态
        /// 
        /// 状态类型
        /// 状态名称
        /// 状态
        public T GetState(string stateName) where T : IState
        {
            return (T)states.Find(m => m.Name == stateName);
        }
        /// 
        /// 获取状态
        /// 
        /// 状态类型
        /// 状态
        public T GetState() where T : IState
        {
            return (T)states.Find(m => m.Name == typeof(T).Name);
        }
        /// 
        /// 状态机刷新事件
        /// 
        public void OnUpdate()
        {
            //若当前状态不为空 执行状态停留事件
            CurrentState?.OnStay();
            //检测所有状态切换条件
            for (int i = 0; i < conditions.Count; i++)
            {
                var condition = conditions[i];
                //条件满足
                if (condition.predicate.Invoke())
                {
                    //源状态名称为空 表示从任意状态切换至目标状态
                    if (string.IsNullOrEmpty(condition.sourceStateName))
                    {
                        Switch(condition.targetStateName);
                    }
                    //源状态名称不为空 表示从指定状态切换至目标状态
                    else
                    {
                        //首先判断当前的状态是否为指定的状态
                        if (CurrentState.Name == condition.sourceStateName)
                        {
                            Switch(condition.targetStateName);
                        }
                    }
                }
            }
        }
        /// 
        /// 状态机销毁事件
        /// 
        public void OnDestroy()
        {
            //执行状态机内所有状态的状态终止事件
            for (int i = 0; i < states.Count; i++)
            {
                states[i].OnTermination();
            }
        }

        /// 
        /// 设置状态切换条件
        /// 
        /// 切换条件
        /// 目标状态名称
        /// 状态机
        public StateMachine SwitchWhen(Func predicate, string targetStateName)
        {
            conditions.Add(new StateSwitchCondition(predicate, null, targetStateName));
            return this;
        }
        /// 
        /// 设置状态切换条件
        /// 
        /// 切换条件
        /// 源状态名称
        /// 目标状态名称
        /// 
        public StateMachine SwitchWhen(Func predicate, string sourceStateName, string targetStateName)
        {
            conditions.Add(new StateSwitchCondition(predicate, sourceStateName, targetStateName));
            return this;
        }

        /// 
        /// 构建状态
        /// 
        /// 状态类型
        /// 状态名称
        /// 状态构建器
        public StateBuilder Build(string stateName = null) where T : State, new()
        {
            Type type = typeof(T);
            T t = (T)Activator.CreateInstance(type);
            t.Name = string.IsNullOrEmpty(stateName) ? type.Name : stateName;
            if (states.Find(m => m.Name == t.Name) == null)
            {
                states.Add(t);
            }
            return new StateBuilder(t, this);
        }

        /// 
        /// 创建状态机
        /// 
        /// 状态机名称
        /// 状态机
        public static StateMachine Create(string stateMachineName = null)
        {
            return FSMMaster.Instance.Create(stateMachineName);
        }
        /// 
        /// 创建状态机
        /// 
        /// 状态机类型
        /// 状态机名称
        /// 状态机
        public static T Create(string stateMachineName = null) where T : StateMachine, new()
        {
            return FSMMaster.Instance.Create(stateMachineName);
        }
        /// 
        /// 销毁状态机
        /// 
        /// 状态机名称
        /// 销毁成功返回true 否则返回false
        public static bool Destroy(string stateMachineName)
        {
            return FSMMaster.Instance.Destroy(stateMachineName);
        }
        /// 
        /// 销毁状态机
        /// 
        /// 状态机类型
        /// 销毁成功返回true 否则返回false
        public static bool Destroy() where T : StateMachine
        {
            return FSMMaster.Instance.Destroy(typeof(T).Name);
        }
        /// 
        /// 获取状态机
        /// 
        /// 状态机名称
        /// 状态机
        public StateMachine Get(string stateMachineName)
        {
            return FSMMaster.Instance.GetMachine(stateMachineName);
        }
        /// 
        /// 获取状态机
        /// 
        /// 状态机类型
        /// 状态机名称
        /// 状态机
        public static T Get(string stateMachineName) where T : StateMachine
        {
            return FSMMaster.Instance.GetMachine(stateMachineName);
        }
        /// 
        /// 获取状态机
        /// 
        /// 状态机类型
        /// 状态机
        public static T Get() where T : StateMachine
        {
            return FSMMaster.Instance.GetMachine(typeof(T).Name);
        }
    }
}

3. StateSwitchCondition类用于设置状态的切换条件,其包含的字段:

        · predicate 切换条件

        · sourceStateName 源状态名称

        · targetStateName 目标状态名称        

该类用于表示当条件predicate满足时,从状态sourceState切换到targetState目标状态

using System;

namespace SK.Framework
{
    /// 
    /// 状态切换条件
    /// 
    public class StateSwitchCondition
    {
        /// 
        /// 条件
        /// 
        public readonly Func predicate;
        /// 
        /// 源状态名称
        /// 
        public readonly string sourceStateName;
        /// 
        /// 目标状态名称
        /// 
        public readonly string targetStateName;

        /// 
        /// 构造函数
        /// 
        /// 切换条件
        /// 源状态名称
        /// 目标状态名称
        public StateSwitchCondition(Func predicate, string sourceStateName, string targetStateName)
        {
            this.predicate = predicate;
            this.sourceStateName = sourceStateName;
            this.targetStateName = targetStateName;
        }
    }
}

4. 定义管理类,其包含的基本行为:

        · Create 创建状态机

        · Destroy 销毁状态机

        · Get 获取状态机

using System;
using UnityEngine;
using System.Collections.Generic;

namespace SK.Framework
{
    /// 
    /// 有限状态机管理器
    /// 
    public class FSMMaster : MonoBehaviour
    {
        #region NonPublic Variables
        private static FSMMaster instance;

        //状态机列表
        private List machines;
        #endregion

        #region Public Properties
        public static FSMMaster Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new GameObject("[SKFramework.FSM]").AddComponent();
                    instance.machines = new List();
                    DontDestroyOnLoad(instance);
                }
                return instance;
            }
        }
        #endregion

        #region NonPublic Methods
        private void Update()
        {
            for (int i = 0; i < machines.Count; i++)
            {
                //更新状态机
                machines[i].OnUpdate();
            }
        }
        private void OnDestroy()
        {
            instance = null;
        }
        #endregion

        #region Public Methods
        /// 
        /// 创建状态机
        /// 
        /// 状态机类型
        /// 状态机名称
        /// 状态机
        public T Create(string stateMachineName = null) where T : StateMachine, new()
        {
            Type type = typeof(T);
            stateMachineName = string.IsNullOrEmpty(stateMachineName) ? type.Name : stateMachineName;
            if (machines.Find(m => m.Name == stateMachineName) == null)
            {
                T machine = (T)Activator.CreateInstance(type);
                machine.Name = stateMachineName;
                machines.Add(machine);
                return machine;
            }
            return default;
        }
        /// 
        /// 销毁状态机
        /// 
        /// 状态机名称
        /// 销毁成功返回true 否则返回false
        public bool Destroy(string stateMachineName)
        {
            var targetMachine = machines.Find(m => m.Name == stateMachineName);
            if (targetMachine != null)
            {
                targetMachine.OnDestroy();
                machines.Remove(targetMachine);
                return true;
            }
            return false;
        }
        /// 
        /// 获取状态机
        /// 
        /// 状态机类型
        /// 状态机名称
        /// 状态机
        public T GetMachine(string stateMachineName) where T : StateMachine
        {
            return (T)machines.Find(m => m.Name == stateMachineName);
        }
        #endregion
    }
}

5. StateBuilder类用于构建状态,便于链式编程

using System;

namespace SK.Framework
{
    /// 
    /// 状态构建器
    /// 
    /// 状态类型
    public class StateBuilder where T : State, new()
    {
        //构建的状态
        private readonly T state;
        //构建的状态所属的状态机
        private readonly StateMachine stateMachine;

        /// 
        /// 构造函数
        /// 
        /// 
        /// 
        public StateBuilder(T state, StateMachine stateMachine)
        {
            this.state = state;
            this.stateMachine = stateMachine;
        }

        /// 
        /// 设置状态初始化事件
        /// 
        /// 状态初始化事件
        /// 状态构建器
        public StateBuilder OnInitialization(Action onInitialization)
        {
            state.onInitialization = () => onInitialization(state);
            return this;
        }
        /// 
        /// 设置状态进入事件
        /// 
        /// 状态进入事件
        /// 状态构建器
        public StateBuilder OnEnter(Action onEnter)
        {
            state.onEnter = () => onEnter(state);
            return this;
        }
        /// 
        /// 设置状态停留事件
        /// 
        /// 状态停留事件
        /// 状态构建器
        public StateBuilder OnStay(Action onStay)
        {
            state.onStay = () => onStay(state);
            return this;
        }
        /// 
        /// 设置状态退出事件
        /// 
        /// 状态退出事件
        /// 状态构建器
        public StateBuilder OnExit(Action onExit)
        {
            state.onExit = () => onExit(state);
            return this;
        }
        /// 
        /// 设置状态终止事件
        /// 
        /// 状态终止事件
        /// 状态构建器
        public StateBuilder OnTermination(Action onTermination)
        {
            state.onTermination = () => onTermination(state);
            return this;
        }
        /// 
        /// 设置状态切换条件
        /// 
        /// 切换条件
        /// 目标状态名称
        /// 状态构建器
        public StateBuilder SwitchWhen(Func predicate, string targetStateName)
        {
            state.SwitchWhen(predicate, targetStateName);
            return this;
        }
        /// 
        /// 构建完成
        /// 
        /// 状态机
        public StateMachine Complete()
        {
            state.OnInitialization();
            return stateMachine;
        }
    }
}

6. Example 编码示例:

using UnityEngine;
using SK.Framework;

public class Foo : MonoBehaviour
{
    public class TestState : State
    {
        public string stringValue;
    }

    private void Start()
    {
        //创建状态机
        var machine = StateMachine.Create()
            //构建状态一
            .Build("状态一")
                //设置状态一初始化事件
                .OnInitialization(state => state.stringValue = "A")
                //设置状态一进入事件
                .OnEnter(state => Debug.Log("进入状态一"))
                //设置状态一停留事件
                .OnStay(state => Debug.Log("状态一"))
                //设置状态一推出事件
                .OnExit(state => Debug.Log("退出状态一"))
                //设置状态一销毁事件
                .OnTermination(state => state.stringValue = null)
            //状态一构建完成
            .Complete()
            //构建状态二
            .Build("状态二")
                //设置状态二进入事件
                .OnEnter(state => Debug.Log("进入状态二"))
                //设置状态二停留事件
                .OnStay(state => Debug.Log("状态二"))
                //设置状态二退出事件
                .OnExit((state => Debug.Log("退出状态二")))
            //状态二构建完成
            .Complete()
            //构建状态三
            .Build("状态三")
                //设置状态三进入事件
                .OnEnter(state => Debug.Log("进入状态三"))
                //设置状态三停留事件
                .OnStay(state => Debug.Log("状态三"))
                //设置状态三退出事件
                .OnExit((state => Debug.Log("退出状态三")))
            //状态三构建完成
            .Complete()
            //添加状态切换条件 当按下快捷键1时 切换至状态一
            .SwitchWhen(() => Input.GetKeyDown(KeyCode.Alpha1), "状态一")
            //添加状态切换条件 当按下快捷键2时 切换至状态二
            .SwitchWhen(() => Input.GetKeyDown(KeyCode.Alpha2), "状态二")
            //添加状态切换条件 当按下快捷键3时 切换至状态三
            .SwitchWhen(() => Input.GetKeyDown(KeyCode.Alpha3), "状态三")
            //为状态一至状态二添加切换条件:若当前状态为状态一时 按下快捷键4 切换至状态二
            .SwitchWhen(() => Input.GetKeyDown(KeyCode.Alpha4), "状态一", "状态二");

        //切换到指定状态
        machine.Switch("状态一");
        //切换到下一状态
        machine.Switch2Next();
        //切换到上一状态
        machine.Switch2Last();
    }
}
关注
打赏
1653184800
查看更多评论
立即登录/注册

微信扫码登录

0.0528s