有限状态机基类(状态的条件,ID,条件ID的字典,增加删除条件,根据条件获取ID,虚方法进入状态,虚方法离开状态,抽象方法状态下的行为,抽象方法状态的触发条件)
public enum Transition
{
NullTransition=0,
LostPlayer,
SeePlayer,
}
public enum StateID
{
NullStateId=0,
Patrol,
Chase,
}
public abstract class FSMState {
protected FSMManager fsmMng;
public FSMState(FSMManager fsmM)
{
fsmMng = fsmM;
}
protected StateID stateId;
public StateID Id { get { return stateId; } }
//条件和状态id的映射
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
public void AddTransition(Transition ts, StateID id)
{
if (ts == Transition.NullTransition || id == StateID.NullStateId || map.ContainsKey(ts))
{
Debug.LogError("出错");
return;
}
map.Add(ts, id);
}
public void DeleteTransition(Transition ts)
{
if (ts == Transition.NullTransition || map.ContainsKey(ts))
{
Debug.LogError("出错");
return;
}
map.Remove(ts);
}
public StateID GetOutputState(Transition trans)
{
if (map.ContainsKey(trans))
{
return map[trans];
}
return StateID.NullStateId;
}
public virtual void DoBeforeEnter() { }
public virtual void DoAfterLeaving() { }
public abstract void Act(GameObject npc);
//判断转换条件
public abstract void Reason(GameObject npc);
}
状态管理类:当前状态,状态ID状态字典,管理中增加状态,管理中删除状态,改变状态,更新状态
public class FSMManager
{
private StateID currentId;
private FSMState currentState;
private Dictionary<StateID, FSMState> StatesDic = new Dictionary<StateID, FSMState>();
public void AddState(FSMState s)
{
if (s == null)
{
Debug.LogError("FSMState不能为空");
return;
}
if (currentState == null)
{
currentId = s.Id;
currentState = s;
}
if (StatesDic.ContainsKey(s.Id))
{
Debug.LogError("状态" + s.Id + "已经存在,无法重复添加");
return;
}
StatesDic.Add(s.Id, s);
}
public void DeleteState(StateID id)
{
if (id == StateID.NullStateId)
{
Debug.LogError("无法删除空状态"); return;
}
if (StatesDic.ContainsKey(id))
{
StatesDic.Remove(id);
}
else
{
Debug.LogError("状态不存在");
}
}
public void ChangeState(Transition tst)
{
if (tst == Transition.NullTransition)
{
Debug.LogError("空条件无法转换");
return;
}
StateID id = currentState.GetOutputState(tst);
if (id == StateID.NullStateId)
{
Debug.LogWarning(currentId + "根据条件" + tst + "无法转换"); return;
}
if (StatesDic.ContainsKey(id))
{
FSMState state = StatesDic[id];
currentState.DoAfterLeaving();
currentId = id;
currentState = state;
currentState.DoBeforeEnter();
}
else
{
Debug.LogError("条件出错" + tst);
}
}
//更新状态
public void Update(GameObject npc)
{
currentState.Act(npc);
currentState.Reason(npc);
}
}
巡逻状态:继承自基类,构造函数(当前id,玩家,巡逻范围),重写抽象类当前状态下的行为,重写抽象类触发当前状态的条件
public class PatrolState:FSMState
{
private Transform PlayerTranform;
public List<Transform> path = new List<Transform>();
public int index = 0;
public PatrolState(FSMManager fsm)
: base(fsm)
{
stateId = StateID.Patrol;
Transform pathGo = GameObject.Find("Path").transform;
PlayerTranform = GameObject.Find("Player").transform;
Transform[] childrens = pathGo.GetComponentsInChildren<Transform>();
foreach (Transform child in childrens)
{
if (child != pathGo)
{
path.Add(child);
}
}
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(path[index].position);
npc.transform.Translate(Vector3.forward * Time.deltaTime * 3);
if (Vector3.Distance(npc.transform.position, path[index].position) < 1)
{
index++;
index %= path.Count;
}
}
public override void Reason(GameObject npc)
{
if (Vector3.Distance(PlayerTranform.position, npc.transform.position) < 3)
{
fsmMng.ChangeState(Transition.SeePlayer);
}
}
}
追踪状态:继承基类,构造函数(当前id,玩家),继承抽象类的表现,继承抽象类的触发条件,
public class ChaseState : FSMState {
private Transform PlayerTranform;
public ChaseState(FSMManager fsm)
: base(fsm)
{
stateId = StateID.Chase;
PlayerTranform = GameObject.Find("Player").transform;
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(PlayerTranform.position);
npc.transform.Translate(Vector3.forward * 2 * Time.deltaTime);
}
public override void Reason(GameObject npc)
{
if (Vector3.Distance(PlayerTranform.position, npc.transform.position) > 6)
{
fsmMng.ChangeState(Transition.LostPlayer);
}
}
}
敌人:初始化的时候把巡逻状态,追踪状态添加到管理类中,每帧更新管理类的Update(行为和转化条件)
public class Enemy : MonoBehaviour {
public FSMManager fsm;
// Use this for initialization
void Start () {
InitFSM();
}
// Update is called once per frame
void Update () {
fsm.Update(this.gameObject);
}
void InitFSM()
{
fsm = new FSMManager();
FSMState patrolState = new PatrolState(fsm);
FSMState ChaseState = new PatrolState(fsm);
patrolState.AddTransition(Transition.SeePlayer, StateID.Chase);
patrolState.AddTransition(Transition.LostPlayer, StateID.Patrol);
fsm.AddState(patrolState);
fsm.AddState(ChaseState);
}
}