stonstad 发表于 2022-7-4 15:56

Unity FSM的原理及实现

按照规矩上代码前先来一键三连,搞错了重来,先来一键三问。
1.什么是FSM?

2.FSM能干什么?

3.为什么要用FSM?


对于上面三个问题,我们一一解答
1.FSM全称是Finite State Machine,中文名是有限状态机,为什么叫有限状态机?有限指的是状态的个数是有限的。

2.FSM是管理一组能相互切换状态的机器。

3.举个例子:我们有如下状态和条件


1.1

我们发现当前处于某个状态下的条件一旦满足,就会切换到另一个状态,也就是条件驱动状态的切换。当状态和条件复杂的时候就需要FSM对这些东西进行管理。


解决了一键三问,我们来看看FSM到底要怎么实现。

还是使用图1.1的例子我们先分析一下,状态对应不同的判断条件,而且以后肯定会增加新条件或者改变条件,如果条件写在对应状态里面,那条件发生改变的时候状态类也要去改动,根据面向对象的模式这违反了开闭原则,我们需要把条件写成类,这样增加条件或者修改条件我们只需要对条件类进行处理。
我们现在知道条件应该做成一个类,那么条件类具体应该干什么呢?


图1.1条件类就是处理条件判断的逻辑,查看自己是否满足了,满足就要切换到下一个状态。

拿检测到移动输入/跳跃输入举例我们来写一些伪代码

class InputMovingCondition{class InputJumpingCondition{

public bool IsInputMoving() {public bool IsInputJumping() {

if(正在移动输入)            if(正在跳跃输入){
    return true                  return true

else                        else

return false                  return false

}                        }

}                        }
说完条件类,我们来看下状态类,状态类到底应该干什么呢?


图1.1,我们发现状态类里面要应该要存放多个条件满足->切换状态的对应关系,然后需要遍历所有条件,看一下哪个条件满足了,满足之后就要去通知状态机切换到对应的状态。而且每个状态要执行的逻辑也各不相同,移动跳跃或是攻击等等。
最后状态机到底干什么呢?


图1.1并没有标出状态机,状态机在后台把控全局类似军师的角色,当前是什么状态,状态怎么切换这些都是状态机去负责的。
根据上面的分析,我们先写以下的代码

条件基类:


条件基类

状态基类:


状态基类

状态机基类:


状态机基类

基本的框架已经搭好了,里面还有些地方我们需要改动,我们接往下走

先看状态基类,mapping这个参数还没有设置,对应关系应该是状态机为状态设置的,状态基类中处理状态的地方不够详细,我们可能需要状态进入和状态退出的事件,这也需要状态机去提供,分析了这些之后再去进行修改
条件基类:


    public abstract class FSMCondition

{

    //我只知道我要条件判断,具体判断什么要让子类重写

    public abstract bool HandleCondition(FSMBase fsmBase);

}
状态基类:


    public abstract class FSMState

{

    //条件->状态的对应关系

    private Dictionary<FSMCondition,FSMState> mapping;

    //由状态机为我们配置映射关系

    public void ConfigMapping(FSMCondition condition, FSMState state)

    {

      mapping.Add(condition,state);

    }

    //这方法让状态机每帧去调用判断

    public void CheckCondition(FSMBase fsmBase)

    {

      //便利自身所有的条件

      foreach(FSMCondition condition in mapping.Keys)

      {

      if(condition.HandleCondition(fsmBase))

      {

          //告诉状态机切换到对应状态,那参数需要FSMBase

          fsmBase.SwitchState(mapping);

          return;

      }

      }

    }

    //状态中自己要干的事,具体做什么还是要子类去重写

      public abstract void OnStateEnter(FSMBase fsmBase);

    public abstract void OnStateStay(FSMBase fsmBase);

    public abstract void OnStateExit(FSMBase fsmBase);

}
状态机基类:


    public abstract class FSMBase : MonoBehaviour

{

    //当前在哪个状态

    protected FSMState currentState;

    //添加状态,并为每个状态去设置应对关系

    protected abstract void AddStateAndConfigMapping();

    //切换状态,切到哪个状态?由状态类调用

    public void SwitchState(FSMState fsmState)

    {

      currentState.OnStateExit(this);//退出旧状态

      currentState = fsmState;

      currentState.OnStateEnter(this);//进入新状态

    }

    protected void Start()

    {

      AddStateAndConfigMapping();

    }

    protected void Update()

    {

      //调用状态类里面的条件判断

      currentState.CheckCondition(this);

      currentState.OnStateStay(this);//正在状态中

    }

}

FSM写完后,我们用图1.1案列去使用一下
状态机类:


用户控制的状态机

状态类:


闲置状态类


移动状态类


跳跃状态类

条件类:


检测跳跃输入


检测跳跃结束


检测移动输入


检测停止移动输入

FSM的简单实现就完成了
页: [1]
查看完整版本: Unity FSM的原理及实现