我想使用有限状态机来处理游戏中的实体状态,特别是针对“Player”实体。我的“Player”将具有诸如怠速、奔跑、跳跃、下落等状态,并需要一种管理这些状态及其之间转换的方式。在面向对象编程环境中,最简单的解决方案是使每个状态成为自己的类,并且有一个名为“handleInput”的方法来接收输入并确定是否应进行状态更改。例如,在“IdleState”中,如果发生move_right或move_left,则状态将更改为新的“RunningState”。这很容易理解和操作,因为状态的行为应该封装在状态中。
但是,在使用实体组件系统中使用FSM时,所有事物都会发生变化。状态不再是对象(因为这与组件系统的灵活性相违背),而是由不同的组件构成的不同排列。例如,“JumpState”可能具有“JumpComponent”、“AirbornMovementComponent”等组件,而“AttackState”可能具有表示攻击的组件,例如“SwingComponent”、“DamageComponent”、“SwordComponent”等。通过重新排列组件,可以创建新状态。系统的工作仅是分别处理这些组件,因为系统不关心状态,它们只关心各个组件。实际的FSM位于由实体持有的“FSMComponent”中。
这很有道理,但涉及到处理状态转换时就有些麻烦了。现在我有一个“InputSystem”,寻找具有“InputComponent”和“FSMComponent”的实体,并尝试根据当前输入更新FSM的状态。然而,这种方法并不太好。
在我看来,FSM处理输入的最佳方式是让每个状态确定它想要如何处理输入以及如何基于该输入过渡到新状态。这回到了OOP实现FSM的方式,违反了ECS的设计,其中组件仅是数据包,并且系统执行所有逻辑。在ECS中,想法是让系统处理状态转换,但这变得复杂,因为每个FSM可能具有不同的条件来在状态之间转换。
不能简单地在“InputSystem”中声明“如果输入为向右移动,则将状态设置为奔跑”。这将是针对玩家特定的,但可能不适用于所有实体。如果有一天我决定使敌人可控制,那么对于
但是,在使用实体组件系统中使用FSM时,所有事物都会发生变化。状态不再是对象(因为这与组件系统的灵活性相违背),而是由不同的组件构成的不同排列。例如,“JumpState”可能具有“JumpComponent”、“AirbornMovementComponent”等组件,而“AttackState”可能具有表示攻击的组件,例如“SwingComponent”、“DamageComponent”、“SwordComponent”等。通过重新排列组件,可以创建新状态。系统的工作仅是分别处理这些组件,因为系统不关心状态,它们只关心各个组件。实际的FSM位于由实体持有的“FSMComponent”中。
这很有道理,但涉及到处理状态转换时就有些麻烦了。现在我有一个“InputSystem”,寻找具有“InputComponent”和“FSMComponent”的实体,并尝试根据当前输入更新FSM的状态。然而,这种方法并不太好。
在我看来,FSM处理输入的最佳方式是让每个状态确定它想要如何处理输入以及如何基于该输入过渡到新状态。这回到了OOP实现FSM的方式,违反了ECS的设计,其中组件仅是数据包,并且系统执行所有逻辑。在ECS中,想法是让系统处理状态转换,但这变得复杂,因为每个FSM可能具有不同的条件来在状态之间转换。
不能简单地在“InputSystem”中声明“如果输入为向右移动,则将状态设置为奔跑”。这将是针对玩家特定的,但可能不适用于所有实体。如果有一天我决定使敌人可控制,那么对于
Player
有效的输入可能不适用于Enemy
。
我的问题: 在ECS中,如何让我的有限状态机(FSM)足够通用和灵活,以允许各种状态转换的实现,而无需在系统本身中进行显式的if/else检查?
如果我方法完全错误,那有更好的解决方案来在实体组件系统中实现FSM吗?