简单有限状态机可直接使用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语句有更好的管理能力,在后续的管理中结构也更加清晰