FSM(有限状态机)

FSM

虽然Unity已经有了动画状态机,但是为了代码的开放封闭原则,这时FSM有限状态机的作用就凸显了出来。

创建控制有限状态机的脚本

先创建一个脚本用来控制有限状态机(FSM),主要用于切换状态。
首先用一个枚举列举出各个状态

public enum StateType
{
    
    
    ldle,
    run,
    jumping,
    dying,
    shooting
}

然后我们需要一个容器来保存当前的状态,用字典存储起来方便随后的更改下一状态随后初始化类,将字典创建,并添加两个增加和设置状态的方法,最后再每一帧执行。代码如下

  //当前在运行什么状态
    private State currentState;
    public StateType stateType;//各个状态的标识符
    //写一个保存所有状态的容器
    private Dictionary<StateType, State> allSaveState;

    public FSMControl()
    {
    
    
        allSaveState = new Dictionary<StateType, State>();
    }

    public void OnTick()//每一帧执行一次
    {
    
    
        currentState?.OnUpdate();
    }
    public void AddState(StateType stateType, State state)
    {
    
    
        if (allSaveState.ContainsKey(stateType))
            return;
        allSaveState.Add(stateType, state);
        
    }
    public void SetState(StateType stateType)//我们需要传一个参数,告诉状态机需要切换到哪一个状态中去
    {
    
    
        if (currentState == allSaveState[stateType]) return;//判断当前状态是否重复
        currentState?.OnEnter();//判断当前状态是否为空
        currentState = allSaveState[stateType];
        currentState.OnEnter();
    }

完整代码如下

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

public enum StateType
{
    
    
    ldle,
    run,
    jumping,
    dying,
    shooting
}
public class FSMControl
{
    
    
    //当前在运行什么状态
    private State currentState;
    public StateType stateType;//各个状态的标识符
    //写一个保存所有状态的容器
    private Dictionary<StateType, State> allSaveState;

    public FSMControl()
    {
    
    
        allSaveState = new Dictionary<StateType, State>();
    }

    public void OnTick()//每一帧执行一次
    {
    
    
        currentState?.OnUpdate();
    }
    public void AddState(StateType stateType, State state)
    {
    
    
        if (allSaveState.ContainsKey(stateType))
            return;
        allSaveState.Add(stateType, state);
        
    }
    public void SetState(StateType stateType)//我们需要传一个参数,告诉状态机需要切换到哪一个状态中去
    {
    
    
        if (currentState == allSaveState[stateType]) return;//判断当前状态是否重复
        currentState?.OnEnter();//判断当前状态是否为空
        currentState = allSaveState[stateType];
        currentState.OnEnter();
    }






}

设置FSM状态机下的各个状态

接下来将展示其中的一个状态,以此类推可以写出其他的状态

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

public  class ldle: State
{
    
    
    private Animator animator;
    private float deltaTime = 5f;
    private FSMControl fsm;
    public ldle(Animator animator,FSMControl fsm)
    {
    
    
        this.animator = animator;
        this.fsm = fsm;
    }
//刚刚进入状态时的行为
    public override void OnEnter()
    {
    
    
        Debug.Log("闲");
    }
//正在进行状态时的行为
    public override void OnUpdate()
    {
    
    
        Debug.Log("站着吧");
        if (deltaTime >= 0)
        {
    
    
            deltaTime -= Time.deltaTime;
            if (deltaTime<0)
            {
    
    
                fsm.SetState((StateType.run));//更改状态为跑
            }
        }
    }
//退出状态后的行为
    public override void OnExit()
    {
    
    
        Debug.Log("该动起来了");
    }
}

可以根据自己的条件去更改切换状态的条件,我这里设置的是5秒后改变状态为跑

添加测试类

但我们将前两个脚本写完,就可以添加测试类,也就是增加各个状态以及设置初始状态的操作后就可以正常运行了

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

public class TestFSM : MonoBehaviour
{
    
    
    private FSMControl fsm;
    private StateType stateType;
    private Animator animator;

    private void Awake()
    {
    
    
        fsm = new FSMControl();
        animator = GetComponentInChildren<Animator>();

        fsm.AddState(StateType.ldle, new ldle(animator,this.fsm));
        fsm.AddState(StateType.run, new run(animator));
        fsm.SetState(StateType.ldle);
    }
    private void Update()
    {
    
    
        fsm.OnTick();
    }
}

FSM的优点

当你需要新的状态时可以直接设置脚本继承FSMControl,保证了代码的开放封闭原则,如果使用动画状态机的切换则需要直接更改原来的代码,运用FSM就可以直接创建新的脚本就能实现增加其他状态了

猜你喜欢

转载自blog.csdn.net/tongmeng_yiran/article/details/129221073