高级有限状态机

简单有限状态机可直接使用switch case语句进行对状态的管理

这里介绍一种高级有限状态机,其框架大致如下

高级有限状态机

        其中FSMState为状态的基类,包含两种枚举类型的变量StateID(状态的ID),Transition(状态的转换条件),FSMSystem用于管理FSMState,而每一个Enemy都拥有一个FSMSystem。

敌人状态类
*****************************************************/

using System.Collections.Generic;
using UnityEngine;

public enum Transition //转换条件
{
    NullTransition=0,
    LostPlayer,
    TheFire,
}

public enum StateID  //敌人状态ID
{
 NullStateID=0,
 Patrol=1,
 Fire,
}

public abstract class  FSMState 
{
    protected StateID stateID;
    public  StateID ID { get { return stateID; } }

    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
    protected FSMsystem fsm;
    public FSMState(FSMsystem fsm)
    {
        this.fsm = fsm;
    }

    public void AddTransition(Transition trans,StateID id)
    {
        if(trans==Transition.NullTransition)
        {
            Debug.LogError("不允许NullTransition");
            return;
        }
        if(id==StateID.NullStateID)
        {
            Debug.LogError("不允许NullStateID");
            return;
        }
        if(map.ContainsKey(trans))
        {
            Debug.LogError("添加转换条件的时候," + trans + "已存在");
            return;
        }
        map.Add(trans,id);
    }

    public void DeleteTransition(Transition trans)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允许NullTransition");
            return;
        }
        if (map.ContainsKey(trans)==false)
        {
            Debug.LogError("删除转换条件的时候," + trans + "并不存在map中");
            return;
        }
        map.Remove(trans);
    }

    public StateID GetOutPutState(Transition trans)
    {
        if(map.ContainsKey(trans))
        {
           return map[trans];
        }
        return StateID.NullStateID;
    }

    public virtual void DoBeforeEntering() { }//进入状态前
    public virtual  void DoAfterLeaving() { }//离开状态后
    public abstract void Act(GameObject NPC);//执行
    public abstract void Reason(GameObject NPC);  //判断转换条件
}
状态管理
*****************************************************/

using System.Collections.Generic;
using UnityEngine;

public class FSMsystem 
{
    private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();
    private StateID CurrentStateID;
    private FSMState CurrentState;

    public void Update(GameObject npc)
    {
        CurrentState.Act(npc);
        CurrentState.Reason(npc);
    }

    public  void AddState(FSMState s)
    {
        if(s==null)
        {
            Debug.LogError("FSMState不能为空");
            return;
        }
        if(CurrentState==null)
        {
            CurrentState = s;
            CurrentStateID = s.ID;
        }
        if(states.ContainsKey(s.ID))
        {
            Debug.LogError("状态" + s.ID + "已经存在无法重复添加");return;
        }
        states.Add(s.ID, s);
    }
    public void DeleteState(StateID id)
    {
        if(id==StateID.NullStateID)
        {
            Debug.LogError("无法删除空状态");
            return;
        }
        if(states.ContainsKey(id)==false)
        {
            Debug.LogError("无法删除不存在的id:" + id);
            return;
        }
        states.Remove(id);
    }
    public void PerformTransition(Transition trans)
    {
        if(trans ==Transition.NullTransition)
        {
            Debug.LogError("无法执行空的转换条件");return;
        }
        StateID id = CurrentState.GetOutPutState(trans);
        if(id== StateID.NullStateID)
        {
            Debug.LogWarning("当前状态" + CurrentStateID + "无法根据转换条件" + trans + "发生转换");return;
        }
        if(states.ContainsKey(id)==false)
        {
            Debug.LogError("在状态机里不存在状态" + id + ",无法进行状态转换");return;
        }
        FSMState state = states[id];
        CurrentState.DoAfterLeaving();
        CurrentState = state;
        CurrentStateID = id;
        CurrentState.DoBeforeEntering();
    }
}

接下来为常见的敌人状态,Patrol,Fire

AI巡逻类
*****************************************************/

using UnityEngine;
public class PatrolState : FSMState
{

    public PatrolState(FSMsystem fsm) : base(fsm)
    {
        stateID = StateID.Patrol;
        //初始化代码
        
    }

    public override void Act(GameObject NPC)
    {
        //该状态需执行的代码啊
    }

    public override void Reason(GameObject NPC)
    {
       if()
        {
           fsm.PerformTransition(Transition.TheFire); //完成条件后进入Fire状态
        }
    }
}
AI开火类
*****************************************************/

using UnityEngine;
public class FireState : FSMState
{

    public PatrolState(FSMsystem fsm) : base(fsm)
    {
        stateID = StateID.Fire;
        //初始化代码
        
    }

    public override void Act(GameObject NPC)
    {
        //该状态需执行的代码啊
    }

    public override void Reason(GameObject NPC)
    {
       if()
        {
           fsm.PerformTransition(Transition.LostPlayer); //完成条件后进入Patrol状态
        }
    }
}

Enemy中添加状态机

敌人控制
*****************************************************/

using UnityEngine;

public class EnemyControl : MonoBehaviour 
{
    private FSMsystem fsm;

    private void Start()
    {
       InitFsm();
    }
    void InitFsm()
    {
        fsm = new FSMsystem();
        FSMState PatrolState = new PatrolState(fsm);
        PatrolState.AddTransition(Transition.TheFire, StateID.Fire);//该状态有几种转换条件即可添加几种
        fsm.AddState(PatrolState);

        FSMState FireState = new FireState(fsm);
        FireState.AddTransition(Transition.LostPlayer, StateID.Patrol);
        fsm.AddState(FireState);
  
    }
    private void Update()
    {
            fsm.Update(this.gameObject, anim,PlayerTF);

    }

此种状态机相比于简单的switch case语句有更好的管理能力,在后续的管理中结构也更加清晰

上一篇:Codeforces 6D Lizards and Basements 2 dfs+暴力


下一篇:福州大学第十六届程序设计竞赛