有限状态机(FSM)

目录

一、什么是有限状态机

二、如何实现

1、简述原理

2、 具体实现


一、什么是有限状态机

有限状态机就是一种用来描述对象不同状态之间如何相互转换的模型,这里最简单的例子就是动画状态机 animator 我们每一次都只能处于一个状态,每一个状态又可以通过一定的条件相互转换。

二、如何实现

1、简述原理

这次我们使用的是ScriptableObject,实现的思路就是从一个状态过度到另外一个状态,我们首先可以想到的就是将状态和条件单独声明出来然后 将两者进行关联。

2、 具体实现

①准备工作:首先创建好如下文件夹

扫描二维码关注公众号,回复: 16000683 查看本文章

 ②具体实现 : 在base下创建如下四个Script

using UnityEngine;

public abstract class ContionOS : ScriptableObject
{
    /// <summary>
    /// 判断条件是否成立
    /// </summary>
    /// <returns>bool</returns>
    public abstract bool SetUP();
}
using UnityEngine;

public class stateMachine : MonoBehaviour
{
    public StateOS currentstate;
    public trasitionOS trasitionos;

    private void Awake()
    {
        trasitionos.Init(this);
    }

    private void Update()
    {
        currentstate?.OnUpdate();
        trasitionos.TryGetEnableCondition();//每一帧都查看是否成立
    }

}
using UnityEngine;

public abstract class StateOS : ScriptableObject
{
    public virtual void OnEnter() { }// 新状态进入 虚方法 子类可实现可不实现
    public abstract void OnUpdate(); // 状态更新 抽象方法子类必须实现该方法 不然会报错
    public virtual void OnExit() { } // 状态退出
    
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[CreateAssetMenu(fileName ="tranlsationos",menuName ="statemachine/create/tranlasition")]
public class trasitionOS : ScriptableObject
{
    //一个状态转变为其他状态可以有很多个条件 stateOS 状态  ContionOS 条件
    private Dictionary<StateOS, List<ContionOS>> _transition = new Dictionary<StateOS, List<ContionOS>>();

    // 转换列表:用来存储状态和条件的装欢关系
    [SerializeField] private List<translationState> currentState = new List<translationState>();

    //状态机 控制状态的更新
    private stateMachine statemachine; 

    public void Init(stateMachine statemachine)
    {
        this.statemachine = statemachine;
        AddTransition();
    }

    // 当前 状态的条件是否成立
    public void TryGetEnableCondition() 
    {
        if (_transition.ContainsKey(statemachine.currentstate)) 
        {
            foreach (var item in _transition[statemachine.currentstate])
            {
                if (item.SetUP()) 
                {
                    translatinon(item);
                }
            }
        }
    }
    /// <summary>
    /// 切换状态
    /// </summary>
    /// <param name="condition">当前状态的条件</param>
    public void translatinon(ContionOS condition) 
    {
        statemachine.currentstate?.OnExit();
        statemachine.currentstate = GetNextstate(condition);
        statemachine.currentstate?.OnEnter();
    }

    public StateOS GetNextstate(ContionOS condition) 
    {
        foreach (var item in currentState)
        {
            if (item.condition == condition && statemachine.currentstate == item.fromState) 
            {
                return item.toState;
            }
        }
        return null;
    }

    /// <summary>
    /// 将状态和条件加入到装欢列表
    /// </summary>
    public void AddTransition() 
    {
        if (currentState.Count != 0) 
        {
            foreach (var item in currentState)
            {
                if (!_transition.ContainsKey(item.fromState))
                {
                    _transition.Add(item.fromState, new List<ContionOS>());
                    _transition[item.fromState].Add(item.condition);
                    Debug.Log("创建并添加");
                }
                else 
                {
                    if (_transition[item.fromState].Contains(item.condition)) 
                    {
                        _transition[item.fromState].Add(item.condition);
                        Debug.Log("存在并再次添加条件");
                    }
                }
            }
        }

    }

    [Serializable]
    private class translationState
    {
        public StateOS fromState;
        public StateOS toState;
        public ContionOS condition;

        private  translationState(StateOS fromState, StateOS toState, ContionOS condition) 
        {
            this.fromState = fromState;
            this.toState = toState;
            this.condition = condition;
        }
        
    }
}

③测试:将stateMachine脚本挂在物体上,并创建如下脚本并根据该脚本创ScriptableObject

实例 以及tranlsasitions实例

 


[CreateAssetMenu(fileName = "condition_idel", menuName = "statemachine/create/Condition/condition_idel")]
public class condition_idel: ContionOS
{
    public override bool SetUP()
    {
        return true;
    }
}
[CreateAssetMenu(fileName = "condition_walk", menuName = "statemachine/create/Condition/condition_walk")]
public class condition_walk : ContionOS
{
    public override bool SetUP()
    {
        return Input.GetKeyDown(KeyCode.W);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "idel", menuName = "statemachine/create/stateos/idel")]
public class idel : StateOS
{
    public override void OnUpdate()
    {
        Debug.Log("正处于idel");
    }
    public override void OnEnter()
    {
        Debug.Log("进入idel");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "walk", menuName = "statemachine/create/stateos/walk")]
public class walk : StateOS
{
    public override void OnUpdate()
    {
        Debug.Log("正处于walk");
    }
    public override void OnEnter()
    {
        Debug.Log("进入walk");
    }
}

根据路径创建相应的实例,将创建好的实例进行如下操作

 

 

这只是一个最基本的fsm而且可以进行拓展。

猜你喜欢

转载自blog.csdn.net/m0_52021450/article/details/127641593