Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finite State Machine Implementation in an Entity Component System

I would like to use a Finite State Machine to handle Entity states in my game. Specifically, for the purpose of this post, I'm going to refer to the Player entity.

My Player is going to have states such as idling, running, jumping, falling, etc... and needs some way to manage these states and the transitions between them. In an OOP environment, the simplest solution was to make each state its own class, and have a method called handleInput take in input and determine if a state change should occur. For example, in the IdleState if either move_right or move_left occurred, the state would change to a new RunningState. This is easy and makes sense because the behavior of a state should be encapsulated in the state.

However, everything changes when you use a FSM in an entity component system. States are no longer objects (because that would go against the flexibility of a component system), but are instead different arrangements of components. The JumpState might have components like JumpComponent, AirbornMovementComponent, etc... whereas the AttackState might have components to represent an attack like SwingComponent, DamageComponent, SwordComponent, etc... The idea is by rearranging the components, new states can be created. The systems job is to simply handle these components separately, because the systems don't care about the state, they only care about the individual components. The actual FSM sits in a FSMComponent held by the entity.

This makes a lot of sense, except for when it comes to handling state transitions. Right now I have an InputSystem that looks for Entities that have an InputComponent and a FSMComponent and attempts to update the state of the FSM based on the current input. However, this doesn't work so well.

The best way (in my opinion) for the FSM to handle input is to have each state determine how it wants to handle input and how to transition to a new state based on that input. This goes back to the OOP way of implementing a FSM, going against the design of an ECS where components are simply data bags and systems do all the logic. In an ECS, the idea would be to have a system handle state transitions, but that gets complicated because every FSM might have different conditions to transition between states.

You can't simply state in the InputSystem "if the input is to move right, then set the state to running". That would be specific to the player, but may not hold true for ALL entities. If one day I decide to make an enemy controllable, the inputs that work for a Player wouldn't be the same inputs for an Enemy.

My question: How can I let my FSM be generic enough and flexible enough in an ECS to allow for various implementations of state transitions without having to do explicit if/else checks in the systems themselves?

Am I approaching this completely the wrong way? If so, what's a better solution for implementing a FSM in an entity component system?

like image 965
Scooter Avatar asked Aug 27 '16 19:08

Scooter


1 Answers

Just riffing off of @fallaciousreasoning's post (and its subsequent comments).

Ash actually has two FSMs that operate at different levels.

First, there is the FSM operating at the Entity level that manages (entity) state transitions by changing the composition of components on an entity as you transition from one state to another.

And secondly there is the FSM operating at the Engine level that manages (engine) state transitions by changing the composition of Systems executed by the engine.

Combined they make for a pretty robust FSM.

The trick is to determine what type of transition you need to work with; one where 'data' composition drives transitions, or one where 'logic' composition drives transitions.

So armed with this new found knowledge lets reason about how this would work.

In more naive approaches to changing component composition, we'd use a number of 'tag' components, along with some lengthy switch statements (or if/else checks) to handle these changes in entity state, ultimately resulting in bloated Systems that do way more than they should. Ash's Entity FSM refines this and avoids those lengthy switch statements (or if/else clauses) by mapping a given component configuration to an identifier and providing a manager that can be used to trigger state transitions. This manager instance can be passed around as a property within a component OR it can be composed/injected as a member of a system.

Alternatively, taking the Engine FSM approach, we break out each bit of state specific logic into their own Systems, and swap them in and out based on the given (engine) state. This method is not without its drawbacks since the absence of a system will affect all entities associated with it. However, its not uncommon to have Systems dedicated to a single entity instance (for example, a player character) so this can prove useful in the right context. Come to think of it affecting entities globally via System swaps may be desirable in some cases as well.

( Note: If the scope of your logic modification needs to be more narrow, you can restrict it to the System without involving the Engine FMS. This can be achieved by implementing the State pattern within a System where the system can change its behavior by delegating to different sub-systems based on state.)

I've seen some ECS frameworks label System compositions as 'Phases', but they fundamentally act as FSMs where the ECS engine processes entities using different sets of systems associated with a given phase.

In closing, data composition is just one half of the equation; how you compose your bits (or blocks) of logic is just as important when trying to implement a FSM within an ECS.

like image 81
TheAddonDepot Avatar answered Oct 12 '22 10:10

TheAddonDepot