有限状态机设计

来源:互联网 发布:yy动态头像源码 编辑:程序博客网 时间:2024/05/16 02:41

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");    }}

原创粉丝点击