DEV Community

Kartik Patel
Kartik Patel

Posted on

State Machine Explained Like You’re 5

What’s a State Machine?

Image description

What if I ask you, what is the name of this game above?

  • It's Mario

Okay, now let's imagine you’re playing Mario. Mario can:

  • Stand
  • Throw fireballs
  • Run
  • Jump
  • Do nothing (idle)
  • Die

But he can’t do all of them at the same time. Mario’s “state” decides what he’s doing right now.

That is where state machines come in handy:

A state machine is just a system that:

  • Knows what state it’s in (standing, running, jumping…)
  • Knows how to switch between states (e.g., press jump → Mario jumps)
  • Doesn’t let you do illegal stuff (e.g., you can’t throw fireballs while dying)

How Does It Work?

The most popular example used while explaining state machines is the Traffic Light.

Think of a traffic light :

  • Green → Yellow → Red
  • It’s not random. You don’t go Green → Green → Red → Red → Yellow.
  • Each state only allows certain transitions.
  • You can't be in 2 states at one time.

Same in games:

  • Can Mario jump from "Dying"? Nope.
  • Can an enemy attack while "Dead"? Nope.

That’s the beauty of a state machine.

Why NOT Just Use If-Else?

if player.is_jumping:
    # Jump logic
elif player.is_running:
    # Run logic
elif player.is_dead:
    # Death logic
Enter fullscreen mode Exit fullscreen mode

Looks cool right now, look at this.

SOURCE ARTIFICIAL INTELLIGNECE, CODE NOT MEANT TO BE RUN ITS JUST FOR EXAMPLE

class Player:
    def __init__(self):
        self.is_idle = True
        self.is_running = False
        self.is_jumping = False
        self.is_shooting = False
        self.is_dead = False
        self.is_crouching = False
        self.is_falling = False
        self.is_attacking = False

    def update(self, inputs):
        if self.is_dead:
            print("Play death animation")
            # Game Over logic
            return

        if inputs.get("press_jump"):
            if self.is_crouching:
                print("Can't jump while crouching... but wait it still happens!")
            self.is_jumping = True
            self.is_idle = False
            self.is_running = False
            print("Jumping...")

        if inputs.get("press_run"):
            if self.is_jumping:
                print("Running mid-air like Naruto (why?)")
            self.is_running = True
            self.is_idle = False
            print("Running...")

        if inputs.get("press_crouch"):
            if self.is_jumping:
                print("Crouching mid-air. This isn’t Fortnite bro.")
            self.is_crouching = True
            self.is_idle = False
            print("Crouching...")

        if inputs.get("press_attack"):
            if self.is_dead:
                print("Attacking while dead? Ghost attacks?")
            else:
                self.is_attacking = True
                print("Attacking!")

        if inputs.get("fall_detected"):
            if self.is_running:
                print("Falling while running? Sure why not.")
            self.is_falling = True
            print("Falling...")

        # Reset states randomly (why? because spaghetti)
        if inputs.get("landed"):
            self.is_jumping = False
            self.is_falling = False
            self.is_idle = True
            self.is_running = False
            self.is_attacking = False
            self.is_crouching = False
            print("Landed. Reset everything!")

player = Player()

# Simulate random inputs
inputs = {
    "press_jump": True,
    "press_run": True,
    "press_crouch": True,
    "press_attack": True,
    "fall_detected": True,
    "landed": False
}

player.update(inputs)
Enter fullscreen mode Exit fullscreen mode

In this code:

  • You can run, crouch, jump, attack, AND fall at the same time.
  • No clear “current state” — it’s just flags all over.
  • Adding ONE more state means more if-else hell.
  • Debugging? I would rather not respond to that.

Now, let's say you usea state machine

SOURCE ARTIFICIAL INTELLIGENCE, CODE NOT MEANT TO BE RUN IT'S JUST FOR EXAMPLE

class State:
    def enter(self, player):
        pass

    def exit(self, player):
        pass

    def handle_input(self, player, inputs):
        pass

class IdleState(State):
    def enter(self, player):
        print("Mario is now standing still (Idle)")

    def handle_input(self, player, inputs):
        if inputs.get("press_run"):
            player.change_state(RunningState())
        elif inputs.get("press_jump"):
            player.change_state(JumpingState())
        elif inputs.get("press_crouch"):
            player.change_state(CrouchingState())
        elif inputs.get("press_attack"):
            player.change_state(AttackingState())
        elif inputs.get("die"):
            player.change_state(DeadState())

class RunningState(State):
    def enter(self, player):
        print("Mario starts running 🏃‍♂️")

    def handle_input(self, player, inputs):
        if inputs.get("release_run"):
            player.change_state(IdleState())
        elif inputs.get("press_jump"):
            player.change_state(JumpingState())
        elif inputs.get("press_attack"):
            player.change_state(AttackingState())
        elif inputs.get("die"):
            player.change_state(DeadState())

class JumpingState(State):
    def enter(self, player):
        print("Mario jumps into the air 🦘")

    def handle_input(self, player, inputs):
        if inputs.get("landed"):
            player.change_state(IdleState())
        elif inputs.get("die"):
            player.change_state(DeadState())

class CrouchingState(State):
    def enter(self, player):
        print("Mario crouches 👀")

    def handle_input(self, player, inputs):
        if inputs.get("release_crouch"):
            player.change_state(IdleState())
        elif inputs.get("die"):
            player.change_state(DeadState())

class AttackingState(State):
    def enter(self, player):
        print("Mario attacks 🔥")

    def handle_input(self, player, inputs):
        if inputs.get("attack_done"):
            player.change_state(IdleState())
        elif inputs.get("die"):
            player.change_state(DeadState())

class DeadState(State):
    def enter(self, player):
        print("Mario has died 💀")

    def handle_input(self, player, inputs):
        pass  # No transitions from Dead

class Player:
    def __init__(self):
        self.state = IdleState()
        self.state.enter(self)

    def change_state(self, new_state):
        self.state.exit(self)
        self.state = new_state
        self.state.enter(self)

    def update(self, inputs):
        self.state.handle_input(self, inputs)

# Example usage
player = Player()

inputs = {
    "press_run": True
}
player.update(inputs)

inputs = {
    "press_jump": True
}
player.update(inputs)

inputs = {
    "landed": True
}
player.update(inputs)

inputs = {
    "die": True
}
player.update(inputs)
Enter fullscreen mode Exit fullscreen mode

In this code:

  • ONE single state active at a time
  • No state weird combos
  • Adding new states is EASY

Why You NEED State Machines in Game Dev

  • Clean code
  • Predictable behavior
  • Easy debugging
  • Handles complex characters/enemies like bosses with multiple phases

TL;DR

  • Our character/enemy is always doing ONE thing at a time.
  • A state machine keeps track of “what” and “what’s next”.
  • It prevents bugs like "walking, shooting, and dying simultaneously".

Outro

TASK

Now… are you gonna JUST read this and scroll TikTok after? Or code a state machine today?

Try this to learn FSM:

  • Traffic lights
  • A vending machine
  • A door
  • A player

Watch These

Till Then, Stay Awesome and Good Bye.

Top comments (0)