有限状态机设计

19 篇文章 0 订阅
10 篇文章 0 订阅

FSM简介

FSM定义:

一个有限状态机是一个设备,或者是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使得一个状态变换到另一个状态,或者是使一个输入或者一种行为的发生。一个有限状态机在任何瞬间只能处在一种状态。

它的优点:

1.编程快速简单,2.易于调试,3.很少的计算开销,4.直觉性,5.灵活性。

简单的框架

主要的两个类,FSMState表示状态,FSMSystem里面维护了一个状态的列表,最后需要一个StateController作为状态的控制器。

FSMState.cs

using UnityEngine;
using System.Collections.Generic;

public enum Transition
{
    NullTransition = 0, // Use this transition to represent a non-existing transition in your system  
    SawPlayer,
    LostPlayer,
    NoHealth,
    ReadytoAim,
    ReadytoShot,
    ReadytoIdle,
    ReadytoAttack,
    ReadytoChasing
}

public enum StateID
{
    NullStateID = 0, // Use this ID to represent a non-existing State in your system  
    Idle,
    Chasing, // jump  
    Attack,
    Shooting,
    Aiming,
    BacktoIdle,//jump  
    Dead,
}


public abstract class FSMState
{
    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();// 过度条件<=>状态ID 映射表
    protected StateID stateID;                                                            // 状态ID
    public StateID ID { get { return stateID; } }                                         // 只读状态ID

    public void AddTransition(Transition trans, StateID id)                               // 添加映射
    {
        // Check if anyone of the args is invalid  
        if (trans == Transition.NullTransition)         //返回
        {
            Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition");
            return;
        }

        if (id == StateID.NullStateID)                  //返回
        {
            Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID");
            return;
        }

        // Since this is a Deterministic FSM,  
        //   check if the current transition was already inside the map  
        if (map.ContainsKey(trans))
        {
            Debug.LogError("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() +
                           "Impossible to assign to another state");
            return;
        }

        map.Add(trans, id);
    }

    /// <summary>  
    /// This method deletes a pair transition-state from this state's map.  
    /// If the transition was not inside the state's map, an ERROR message is printed.  
    /// </summary>  
    public void DeleteTransition(Transition trans)                                      // 删除映射
    {
        // Check for NullTransition  
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("FSMState ERROR: NullTransition is not allowed");
            return;
        }

        // Check if the pair is inside the map before deleting  
        if (map.ContainsKey(trans))
        {
            map.Remove(trans);
            return;
        }
        Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() +
                       " was not on the state's transition list");
    }

    /// <summary>  
    /// This method returns the new state the FSM should be if  
    ///    this state receives a transition and   
    /// </summary>  
    public StateID GetOutputState(Transition trans)                                // 获取输出状态ID
    {
        // Check if the map has this transition  
        if (map.ContainsKey(trans))
        {
            return map[trans];
        }
        return StateID.NullStateID;
    }

    /// <summary>  
    /// This method is used to set up the State condition before entering it.  
    /// It is called automatically by the FSMSystem class before assigning it  
    /// to the current state.  
    /// </summary>  
    public virtual void DoBeforeEntering() { }                                     // 进入状态

    /// <summary>  
    /// This method is used to make anything necessary, as reseting variables  
    /// before the FSMSystem changes to another one. It is called automatically  
    /// by the FSMSystem before changing to a new state.  
    /// </summary>  
    public virtual void DoBeforeLeaving() { }                                      // 离开状态

    /// <summary>  
    /// This method decides if the state should transition to another on its list  
    /// NPC is a reference to the object that is controlled by this class  
    /// </summary>  
    public abstract void Reason(FSMSystem fsms);  // 检测

    /// <summary>  
    /// This method controls the behavior of the NPC in the game World.  
    /// Every action, movement or communication the NPC does should be placed here  
    /// NPC is a reference to the object that is controlled by this class  
    /// </summary>  
    public abstract void Act(GameObject player = null, GameObject npc = null);      // 执行
}

FSMSystem.cs

using UnityEngine;
using System.Collections.Generic;


public class FSMSystem : MonoBehaviour
{
    private List<FSMState> states;                                                      //状态集合
    // The only way one can change the state of the FSM is by performing a transition  
    // Don't change the CurrentState directly  
    private StateID currentStateID;                                                     //当前状态ID
    public StateID CurrentStateID { get { return currentStateID; } }
    private FSMState currentState;                                                      //当前状态
    public FSMState CurrentState { get { return currentState; } }
    public StateID defaultState { set { defaultState = value; } get { return defaultState; } }  //默认状态ID

    public void resetToDefaultState()                                                   //重置默认
    {
        //currentState = states[0];
        //currentStateID = states[0].ID;
        /*for(int i =0; i< states.Count; i++) 
        { 
            if(states[i].ID == defaultState) 
            { 
                currentState = states[i]; 
                currentStateID = states[i].ID; 
            } 
        }*/
    }

    public FSMSystem()
    {
        states = new List<FSMState>();
    }

    /// <summary>  
    /// This method places new states inside the FSM,  
    /// or prints an ERROR message if the state was already inside the List.  
    /// First state added is also the initial state.  
    /// </summary>  
    public void AddState(FSMState s)                                        //增加状态
    {
        // Check for Null reference before deleting  
        if (s == null)
        {
            Debug.LogError("FSM ERROR: Null reference is not allowed");
        }

        // First State inserted is also the Initial state,  
        //   the state the machine is in when the simulation begins  
        if (states.Count == 0)
        {
            states.Add(s);
            currentState = s;
            currentStateID = s.ID;
            return;
        }

        // Add the state to the List if it's not inside it  
        foreach (FSMState state in states)
        {
            if (state.ID == s.ID)
            {
                Debug.LogError("FSM ERROR: Impossible to add state " + s.ID.ToString() +
                               " because state has already been added");
                return;
            }
        }
        states.Add(s);
    }

    /// <summary>  
    /// This method delete a state from the FSM List if it exists,   
    ///   or prints an ERROR message if the state was not on the List.  
    /// </summary>  
    public void DeleteState(StateID id)                                     //删除状态
    {
        // Check for NullState before deleting  
        if (id == StateID.NullStateID)
        {
            Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
            return;
        }

        // Search the List and delete the state if it's inside it  
        foreach (FSMState state in states)
        {
            if (state.ID == id)
            {
                states.Remove(state);
                return;
            }
        }
        Debug.LogError("FSM ERROR: Impossible to delete state " + id.ToString() +
                       ". It was not on the list of states");
    }

    /// <summary>  
    /// This method tries to change the state the FSM is in based on  
    /// the current state and the transition passed. If current state  
    ///  doesn't have a target state for the transition passed,   
    /// an ERROR message is printed.  
    /// </summary>  
    public void PerformTransition(Transition trans)                                      //执行过度状态
    {
        // Check for NullTransition before changing the current state  
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
            return;
        }

        // Check if the currentState has the transition passed as argument  
        StateID id = currentState.GetOutputState(trans);
        if (id == StateID.NullStateID)
        {
            Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
                           " for transition " + trans.ToString());
            return;
        }

        // Update the currentStateID and currentState         
        currentStateID = id;
        foreach (FSMState state in states)
        {
            if (state.ID == currentStateID)
            {
                // Do the post processing of the state before setting the new one  
                currentState.DoBeforeLeaving();

                currentState = state;

                // Reset the state to its desired condition before it can reason or act  
                currentState.DoBeforeEntering();
                break;
            }
        }

    } // PerformTransition()  

    //
    void Awake()
    {
        FSMState Chasing = new ChasingState();
        Chasing.AddTransition(Transition.LostPlayer, StateID.Idle);
        AddState(Chasing);
        FSMState Idle = new IdleState();
        Idle.AddTransition(Transition.SawPlayer, StateID.Chasing);
        AddState(Idle);


    }

    //
    void Update()
    {
        if (currentState!=null)
        {
            currentState.Act();
            currentState.Reason(this);
        }
    }


    public bool Chasing = false;
    public bool Idle = false;
    void OnGUI()
    {
        if (GUI.Button(new Rect(50,50,100,50),"Chasing"))
        {
            Chasing = true;
            Idle = false;

        }
        if (GUI.Button(new Rect(50, 150, 100, 50), "Idle"))
        {
            Chasing = false;
            Idle = true;

        }
    }

}


状态实例

IdleState.cs

using UnityEngine;

public class IdleState : FSMState
{

    public IdleState()
    {
        stateID = StateID.Idle;
    }

    float time = 0;
    float timeD = 1;

    public override void Act(GameObject player = null, GameObject npc = null)
    {
        
        time += Time.deltaTime;
        if (time > timeD)
        {
            time = 0;
            Debug.Log("@@ IdleState Act");
        }
    }

    public override void Reason(FSMSystem fsms)
    {
        //判断条件
        if (fsms.Chasing)
        {
            fsms.PerformTransition(Transition.SawPlayer);
            Debug.Log("@@ IdleState Reason");
        }
    }

    public override void DoBeforeLeaving()
    {
        Debug.Log("@@ IdleState Leaving");
    }

    public override void DoBeforeEntering()
    {
        Debug.Log("@@ IdleState Entering");
    }
}


ChasingState.cs

using UnityEngine;

public class ChasingState : FSMState
{


    public ChasingState()
    {
        stateID = StateID.Chasing;
    }

    float time = 0;
    float timeD = 1;

    public override void Act(GameObject player = null, GameObject npc = null)
    {
       
        time += Time.deltaTime;
        if (time > timeD)
        {
            time = 0;
            Debug.Log("@@ ChasingState Act");
        }
    }

    public override void Reason(FSMSystem fsms)
    {
        //判断条件
        if (fsms.Idle)
        {
            fsms.PerformTransition(Transition.LostPlayer);
            Debug.Log("@@ ChasingState Reason");
        }

    }

    public override void DoBeforeLeaving()
    {
        Debug.Log("@@ ChasingState Leaving");
    }

    public override void DoBeforeEntering()
    {
        Debug.Log("@@ ChasingState Entering");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值