A Finite State Machine is a concept first, and a programming pattern second. It's a way to organize or visualize your code by breaking it down into separate, distinct, and exclusive states. Each state has its own code and behavior, and the machine can only be in one state at a time.
For example, a character in a game can be in an idle state (standing still), a running state, or a jumping state. With a state machine, you can ensure that only one of these states is active at any given time, and only the code for that state is executed every frame.
There are four conditions for talking about a state machine:
- There is a fixed number of states.
- The machine can be in one and only one state at a time.
- The machine receives events like inputs or signals.
- The states have transitions mapped to events. When a state receives a given event, it tells the machine to transition to the corresponding state.
You use finite state machines to:
- Make it easier to add new states and behaviors to your game. For example, you can add a new state for a character to glide without changing the code for the other states.
- Control better the transitions between states, ensuring that the character doesn't play the wrong animation in a given state, for example.
- Split your code into separate states, making reading and isolating behaviors easier.
Finite state machines are used in many areas of game development, like AI, animation, and UI. They are also used in other fields like robotics, control systems, and computer science.
While a large portion of every day code is actually finite state machines, when people talk about finite state machines, they usually refer to a specific pattern that is more explicit about the states and transitions.
Because state machines are a way to organize the code for humans, the best implementations will depend on the human reading them. If the state machine doesn't make the code simpler for you, it's not a good state machine.
Typically, the most universally useful state machine implementations come with a graphical representation of the states and transitions. This way, you can see at a glance how the states are connected and what events trigger transitions. For example, in the Javascript world, XState is a popular library that allows you to define state machines in a visual way, and has a companion tool to visualize the state machine: Stately.
But that doesn't mean that authoring state machines in code is bad! As long as it helps you make sense of your own code, then it's a good abstraction. Here's an example of a simple state machine in GDScript without any framework or boilerplate, using simply an enum:
extends CharacterBody2D
enum State { IDLE, RUNNING, JUMPING, FALLING }
var current_state := State.IDLE
const SPEED = 300.0
const AIR_SPEED = 200.0
const JUMP_VELOCITY = -400.0
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
@onready var label: Label = %Label
func _physics_process(delta: float) -> void:
var direction := Input.get_axis("ui_left", "ui_right")
label.text = State.keys()[current_state]
match current_state:
State.FALLING:
if is_on_floor():
current_state = State.IDLE
else:
velocity.y += gravity * delta
velocity.x = direction * AIR_SPEED
State.IDLE:
if not is_on_floor():
current_state = State.FALLING
elif Input.is_action_just_pressed("ui_accept"):
current_state = State.JUMPING
elif direction:
current_state = State.RUNNING
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
State.RUNNING:
velocity.x = direction * SPEED
if not direction:
current_state = State.IDLE
elif Input.is_action_just_pressed("ui_accept"):
current_state = State.JUMPING
State.JUMPING:
velocity.y = JUMP_VELOCITY
current_state = State.IDLE
move_and_slide()
See Also
Related terms in the Glossary