找回密码
 立即注册
查看: 305|回复: 0

Unity FSM的原理及实现

[复制链接]
发表于 2022-7-4 15:56 | 显示全部楼层 |阅读模式
按照规矩上代码前先来一键三连,搞错了重来,先来一键三问。
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[condition]);

          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的简单实现就完成了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-19 04:13 , Processed in 0.091458 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表