有限状态机FSM导图
- 第一步
开发FSMState核心类
首先添加两个枚举类,用来定义状态和转换条件
public enum StateID
{
nullStateID,
walk,
chase
}
public enum Transition
{
nullTransition,
lookEnemy,
lostEnemy
}
public abstract class FSMState
{
protected StateID _StateID;
public StateID stateID { get { return _StateID; } }
//存储转换状态的集合
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
//添加转换条件
public void AddTransition(Transition trans,StateID id)
{
if(trans == Transition.nullTransition)
{
Debug.LogError("添加的转换条件为空");return;
}
if(id == StateID.nullStateID)
{
Debug.LogError("添加到状态为空");return;
}
if (map.ContainsKey(trans))
{
Debug.LogError("添加的转换条件已存在");return;
}
map.Add(trans, id);
}
//删除转换条件
public void DeleteTransition(Transition trans)
{
if(trans == Transition.nullTransition)
{
Debug.LogError("删除的条件为空");return;
}
if (!map.ContainsKey(trans))
{
Debug.LogError("删除的条件不存在");return;
}
map.Remove(trans);
}
//根据转换条件得到响应状态
public StateID GetOutputState(Transition trans)
{
if (map.ContainsKey(trans))
{
return map[trans];
}
return StateID.nullStateID;
}
//在特定状态需要做的事
public abstract void Act(GameObject npc);
//判断转换条件
public abstract void Reason(GameObject npc);
}
2.第二步
开发FSMSystem核心类
public class FSMSystem
{
//定义字典,用来存放状态ID所对应的状态
private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();
//定义当前状态
private StateID currentStateID;
private FSMState currentFSMState;
//添加状态
public void AddState(FSMState s)
{
if(s == null)
{
Debug.LogError("添加的状态为空");return;
}
if(currentFSMState == null)
{
currentFSMState = s;
currentStateID = s.stateID;
}
if (states.ContainsKey(s.stateID))
{
Debug.LogError("已存在该状态");return;
}
states.Add(s.stateID, s);
}
//删除状态
public void DeleteState(StateID id)
{
if(id == StateID.nullStateID)
{
Debug.LogError("状态为空");return;
}
if (!states.ContainsKey(id))
{
Debug.LogError("删除状态不存在");return;
}
states.Remove(id);
}
//根据转换条件实现状态的转换
public void PerformTransition(Transition trans)
{
if(trans == Transition.nullTransition)
{
Debug.LogError("无法执行空的转换条件");return;
}
StateID id = currentFSMState.GetOutputState(trans);
if(id == StateID.nullStateID)
{
Debug.LogError("当前转台无法根据转换条件进行转换");return;
}
if (!states.ContainsKey(id))
{
Debug.LogError("当前状态不存在");return;
}
FSMState state = states[id];
currentStateID = id;
currentFSMState = state;
}
}
3.第三步
为FSMState类添加构造方法
public FSMSystem system;
public FSMState(FSMSystem system)
{
this.system = system;
}
4.第四步
开发子状态Walk状态和Chase状态
public class WalkState : FSMState
{
private List<Transform> path = new List<Transform>();
private int index = 0;
//Unity中需创建一个Enemy,需要包含Transform组件
private Transform enemy;
public WalkState(FSMSystem system) : base(system)
{
_StateID = StateID.walk;
//Path为博主在Unity中定义的一个空的GameObject,其中子物体包含了三个点,只要有Transform组件即可
Transform pathTransform = GameObject.Find("Path").transform;
Transform[] chindren = pathTransform.GetComponentsInChildren<Transform>();
foreach (Transform item in chindren)
{
if(item != pathTransform)
{
path.Add(item);
}
}
enemy = GameObject.Find("Enemy").transform;
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(path[index].position);
npc.transform.Translate(Vector3.forward*Time.deltaTime*10);
if (Vector3.Distance(npc.transform.position, path[index].position) < 0.5)
{
index++;
index %= path.Count;
}
}
public override void Reason(GameObject npc)
{
if (Vector3.Distance(npc.transform.position, enemy.position) < 3)
{
system.PerformTransition(Transition.lookEnemy);
}
}
}
public class ChaseState : FSMState
{
private Transform enemyTransform;
public ChaseState(FSMSystem system) : base(system)
{
//定义当前类的状态
_StateID = StateID.chase;
enemyTransform= GameObject.Find("Enemy").transform;
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(enemyTransform.position);
npc.transform.Translate(Vector3.forward * Time.deltaTime * 20);
}
public override void Reason(GameObject npc)
{
if (Vector3.Distance(enemyTransform.position, npc.transform.position) > 6)
{
system.PerformTransition(Transition.lostenemy);
}
}
}
5.第五步
在FSMSystem添加Update方法,用来每一帧执行Act和Reason方法
public void update(GameObject npc)
{
currentFSMState.Act(npc);
currentFSMState.Reason(npc);
}
6.第六步
开发Player类,并挂载到Unity中Player游戏物体上
public class Player : MonoBehaviour
{
private FSMSystem fsm;
// Start is called before the first frame update
void Start()
{
fsm = new FSMSystem();
FSMState walkState = new WalkState(fsm);
walkState.AddTransition(Transition.lookEnemy, StateID.chase);
FSMState chaseState = new ChaseState(fsm);
chaseState.AddTransition(Transition.lostEnemy, StateID.walk);
fsm.AddState(walkState);
fsm.AddState(chaseState);
}
// Update is called once per frame
void Update()
{
fsm.update(this.gameObject);
}
}
完成以上步骤即可初步实现Player自动行走,当距离范围内有敌人时便会追击敌人,当敌人离远了,又会回到原来的地点行走的功能。
需要添加其他状态只需要写好状态类继承自FSMState,重写Act和Reason方法。然后在Player里将状态添加到状态机里即可。