我是靠谱客的博主 强健手机,最近开发中收集的这篇文章主要介绍有限状态机什么是有限状态机?为什么用有限状态机?怎么用有限状态机?附加,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

什么是有限状态机?

维基百科解释:有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机(英语:finite-state automaton,缩写:FSA),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。

  • 一般情况下每个状态的生命周期为 进入状态、状态持续、离开状态,然后再由一个控制器来进行状态注册以及控制各个状态的切换
  • 同时只能存在一种状态

为什么用有限状态机?

在实际开发过程中,我们经常需要处理各种状态的切换,一般情况下我们用if…else if…或者switch case 就可以解决。但是在遇到一些比较复杂的逻辑,需要很多的状态,并且有一些状态还要处理一些复杂的逻辑,这个时候再用上面的方法就显得有点捉襟见肘了,严重影像后期的维护。有限状态机就是为了解决这种多状态切换的一种数学模型。

怎么用有限状态机?

根据定义,首先我定义一个状态基类或者接口,这里为了方便后期的扩展,可能有些状态需要多继承,例如同时继承状态接口和Monobehaviour,所以我选择使用接口来定义状态,如下:

public interface IState
{
    void OnEnter(params object[] param);
    void OnStay(params object[] param);
    void OnExit(params object[] param);
}

可以看到,我定义的状态包含了三个方法体,分别是OnEnter(进入状态)、OnStay(状态持续)、OnExit(离开状态) 所以这个状态接口就可以模拟基本状态的生命周期。

接下来我定义一个状态机的控制对象,这里也用接口定义。如下

public interface IFSMController
{
    Dictionary<Type, IState> stateDict { get; }
    IState currentState { get; }

    void AddState(IState state);
    void RemoveState(Type type);
    void ClearState();

    void ToState<T>()where T:IState;
    IState GetState<T>();
    void OnUpdate();
}

列个表格来解释一下每个属性或者方法体的作用吧

字段或属性解释
stateDict状态字典
currentState当前状态
AddState增加一个状态
RemoveState移除一个状态
ClearState清空状态
ToState切换到目标状态
GetState根据类型得到状态对象
OnUpdate更新

其实常规的状态字典定义中,有使用唯一flag做key的,也有使用枚举做key的,我这里之所以用Type做key是因为,省去了每次增加状态时都需要增加flag或者枚举类型。

基础的有限状态机模型已经搭建完毕,下面做一个小测试吧。
假设我有一个人物,只有三种状态 Idle、Walk、Run初始状态为Idle,点击A键进入Walk状态,点击S键进入Run状态,点击D键重新进入Idle状态。
从状态定义开始写吧:

using UnityEngine;

namespace FSM_Test
{
    public class Idle : IState
    {
        public void OnEnter(params object[] param)
        {
            Debug.Log("进入Idle状态");
        }

        public void OnStay(params object[] param)
        {
           // Debug.Log("持续 Idle状态");
        }

        public void OnExit(params object[] param)
        {
            Debug.Log("离开Idle状态");
        }
    }
    
    public class Walk : IState
    {
        public void OnEnter(params object[] param)
        {
            Debug.Log("进入Walk状态");
        }

        public void OnStay(params object[] param)
        {
            
        }

        public void OnExit(params object[] param)
        {
            Debug.Log("离开Walk状态");
        }
    }

    public class Run : IState
    {
        public void OnEnter(params object[] param)
        {
            Debug.Log("进入Run状态");
        }

        public void OnStay(params object[] param)
        {
            
        }

        public void OnExit(params object[] param)
        {
            Debug.Log("离开Run状态");
        }
    }

}

FSM控制器如下:

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

public class FSMController : IFSMController
{
    public Dictionary<Type, IState> stateDict { get; private set; }
    public IState currentState { get; private set; }
    
    public FSMController()
    {
        stateDict=new Dictionary<Type, IState>();
    }

    public void AddState(IState state)
    {
        if (state == null) return;
        Type type = state.GetType();
        if (stateDict.ContainsKey(type))
        {
            Debug.LogFormat("AddState 警告!【{0}】无需重复添加",type);
            return;
        }
        stateDict.Add(type,state);
    }

    public void RemoveState(Type type)
    {
        if (!stateDict.ContainsKey(type)) return;
        stateDict.Remove(type);
    }

    public void ClearState()
    {
        stateDict.Clear();
    }

    public void ToState<T>()where T:IState
    {
        IState state = GetState<T>();
        if (state == null) return;
        currentState?.OnExit();
        state.OnEnter();
        currentState = state;
    }

    public IState GetState<T>()where T:IState
    {
        if (stateDict == null || stateDict.Count == 0) return null;
        Type type = typeof(T);
        if (!stateDict.ContainsKey(type)) return null;
        return stateDict[type];
    }

    public void OnUpdate()
    {
        currentState?.OnStay();
    }

    public bool IsCurrentState<T>() where T:IState
    {
        return currentState.GetType() == typeof(T);
    }
}

测试启动

using UnityEngine;

namespace FSM_Test
{
    public class DemoTest : MonoBehaviour
    {
        private FSMController fsmController;
        void Start()
        {
            fsmController=new FSMController();
            fsmController.AddState(new Idle());
            fsmController.AddState(new Walk());
            fsmController.AddState(new Run());
            fsmController.ToState<Idle>();
        }

        void Update()
        {
            fsmController?.OnUpdate();
            if (Input.GetKeyDown(KeyCode.A))fsmController.ToState<Walk>();
            if (Input.GetKeyDown(KeyCode.S))fsmController.ToState<Run>();
            if (Input.GetKeyDown(KeyCode.D))fsmController.ToState<Idle>();
        }
    }
}

在这里插入图片描述

附加

根据定义我们知道,一个状态机我们只能同时存在一种状态,但是,有时候我们需要同时存在多个状态,例如,蹲走,跳走等这些多个状态混合的逻辑时,这个时候很显然一个状态机已经无法满足正常需求了。所以碰到这种情况,我们可以考虑用两个状态机,一个负责姿态,一个负责移动,这样就能解决多状态共存的问题。
后期准备抽时间写一个有限状态机做人物控制的Demo。

最后

以上就是强健手机为你收集整理的有限状态机什么是有限状态机?为什么用有限状态机?怎么用有限状态机?附加的全部内容,希望文章能够帮你解决有限状态机什么是有限状态机?为什么用有限状态机?怎么用有限状态机?附加所遇到的程序开发问题。

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

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

评论列表共有 0 条评论

立即
投稿
返回
顶部