【unity】FSM有限状态机

前言

开发时,难免会遇到对象需要在某几个状态之间不停切换的问题,尤其是敌人对象。对于类似的问题,使用FSM有限状态机是一个不错的解决方案。今天特地抽空来总结一下FSM的相关内容。

引子

为什么要用FSM有限状态机?

小明在写敌人类时,使用了大量的if-else来控制敌人的行动,但随着敌人的行动越来越复杂,他新增的if-else也越来越多。最后逻辑糊成一坨,不堪入目。

显然,我们迫切地需要一个具有良好拓展性的,结构清晰的解决方案,让我们不至于重蹈小明的覆辙。

组成

定义一个抽象基类BaseState,其他状态类继承自该类

public abstarct class BaseState
{
	public abstract void EnterState(NPC npc);   //进入该状态时调用一次
	public abstract void Action(NPC npc);  //该状态需要执行的动作
	public abstract void CheckSwtich(NPC npc);  //检测是否要转到其他状态
	public abstract void ExitState(NPC npc);   //离开该状态时调用一次
}

其他类举例:AttackState

public class AttackState : BaseState
{
	public override void EnterState(NPC npc){ /*具体实现略*/ }
	public override void Action(NPC npc) { /*具体实现略*/ }
	public override void CheckSwtich(NPC npc) { /*具体实现略*/ }
	public override void ExitState(NPC npc) { /*具体实现略*/ }
}

其他类举例:IdleState

public class IdleState : BaseState
{
	public override void EnterState(NPC npc){ /*具体实现略*/ }
	public override void Action(NPC npc) { /*具体实现略*/ }
	public override void CheckSwtich(NPC npc) { /*具体实现略*/ }
	public override void ExitState(NPC npc) { /*具体实现略*/ }
}

由 FSMSystem 统一管理

public class FSMSystem
{
	private BaseState currentState;
	private BaseState attackState = new AttackState();
	private BaseState idleState = new IdleState();
	
	public void Init(NPC npc) { /*具体实现略*/ }
	
	public void FSMAwake(NPC npc)
	{
		Init(npc);
		currentState = idleState;
	}
	
	public void FSMUpdate(NPC npc)
	{
		currentState.Action(npc);
		currentState.CheckSwtich(npc);
	}
	
	public void TransitionToState(BaseState state)
	{
		currentState = state;
		currentState.EnterState(npc);
	}
)

我们发现各个状态没有继承自 MonoBehaviour ,无法直接挂载在游戏对象上。我们可以利用 NPC 类来管理 FSMSystem。

public class NPC : MonoBehaviour
{
	private FSMSystem fsm;
	private void Awake()
	{
		fsm.FSMAwake(this);
	}
	private void Update()
	{
		fsm.FSMUpdate(this);
	}
}

FSM的写法不唯一,像如上代码,可以取消 NPC 和 FSMSystem 之间的组合关系,将FSM中的成员直接并入 NPC 中,在某些应用场景下,这样处理可能更加适用;还可以利用字典和枚举类型,使让代码架构更加清晰......我这里的举例也只是抛砖引玉。

理解了FSM的工作机制,通过改善和优化代码,能使其更加贴合我们当前遇到的问题。

小结

1.对象在任一时刻只能处于某一种状态,而非某几个状态的叠加。
2.对象只能在有限个状态间互相切换。

利用FSM有限状态机,我们能很方便地拓展代码,如果对象有新的行为状态,我们也只需要创建新的状态类,使其继承自状态基类。这无疑降低了拓展难度。但在设计新的状态类时,要考虑清楚:对象的某一状态的入口是什么,执行过程是什么,状态出口是什么,想清楚了再动手。

posted @ 2022-04-03 21:08  AshScops  阅读(177)  评论(0编辑  收藏  举报