using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//装换条件
public enum Transition
{
NullTransition=0,
SeePlayer,
LostPlayer
}
public enum StateID
{
NullStateID=0,
Patrol,
Chase
}
//FSMState所有状态的基类
//每个状态单独一个类,
//每个状态要一个StateId(枚举类型),方便让FSMSystem来管理
public abstract class FSMState {
protected StateID stateID;
public StateID ID
{
get { return stateID; }
}
//每个子类都有一个映射
//protected方便子类访问
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
protected FSMSystem fsm; //这个状态归哪个System管理的
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+"已经存在于map"); return;
}
map.Add(trans, id);
}
public void DeleteTranition(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;
using System.Collections.Generic;
using UnityEngine;
//FSMSystem管理所有的状态和条件跳转
public class FSMSystem {
//存储状态机的所有状态
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("无法不存在的状态"); return;
}
states.Remove(id);
}
//执行转换条件
public void PerformTrasition(Transition trans)
{
if (trans == Transition.NullTransition)
{
Debug.LogError("无法执行空的转换条件"); return;
}
StateID id= currentState.GetOutPutState(trans); //根据转换条件获得对应的状态
if (id == StateID.NullStateID) //不需要转换
{
Debug.LogWarning("当前状态" + currentState + "无法根据转换条件" + trans + "发生转换"); return;
}
if (states.ContainsKey(id) == false)
{
Debug.LogError("状态机里面不存在状态"+id+"无法进行转换"); return;
}
FSMState state = states[id]; //根据id获得要转换状态
currentState.DoAfterLeaving();//旧的状态进入之前要做什么
currentState = state;
currentStateID = id;
currentState.DoBeforeEntering();//新状态进入之前要作什么
}
}
用法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//巡逻状态
public class PatrolState : FSMState
{
private List<Transform> path=new List<Transform>();
private int index = 0;
private Transform playerTransform;
//构造函数
public PatrolState(FSMSystem fsm):base(fsm)
{
stateID = StateID.Patrol;
Transform pathTransform = GameObject.Find("Path").transform;
Transform[] childern= pathTransform.GetComponentsInChildren<Transform>();
foreach (Transform child in childern)
{
if (child != pathTransform)
{
path.Add(child);
}
}
playerTransform = GameObject.Find("Player").transform;
}
//当前状态应该做的事情
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(playerTransform.position, npc.transform.position) < 2)
{
fsm.PerformTrasition(Transition.SeePlayer);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//追逐状态
public class ChaseState : FSMState
{
private Transform playerTransform;
public ChaseState( FSMSystem fsm) : base(fsm)
{
stateID = StateID.Chase;
playerTransform = GameObject.Find("Player").transform;
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(playerTransform.position);
npc.transform.Translate(Vector3.forward*2*Time.deltaTime);
}
public override void Reason(GameObject npc)
{
if (Vector3.Distance(playerTransform.position, npc.transform.position) > 6)
{
fsm.PerformTrasition(Transition.LostPlayer);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
private FSMSystem fsm;
void InitFSM()
{
fsm = new FSMSystem();
FSMState patrolState = new PatrolState(fsm);
fsm.AddState(patrolState);
FSMState chaseState=new ChaseState(fsm);
fsm.AddState(chaseState);
patrolState.AddTransition(Transition.SeePlayer, StateID.Chase);
chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol);
}
// Use this for initialization
void Start () {
InitFSM();
}
// Update is called once per frame
void Update () {
fsm.Update(this.gameObject);
}
}