Skip to content
Development
Skill

/state-machine

Generic state machine patterns — IState interface, StateMachine<T>, game state management (menu/gameplay/pause), enemy AI states, hierarchical FSM. Load when implementing state-driven behavior.

From plugin
everything-claude-unity
2442 skills20 agents27 commands
Install
$ npx -y skills add XeldarAlz/everything-claude-unity --skill state-machine --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/state-machine

Context preview

The summary Claude sees to decide when to auto-load this skill.

Generic state machine patterns — IState interface, StateMachine<T>, game state management (menu/gameplay/pause), enemy AI states, hierarchical FSM. Load when implementing state-driven behavior.

SKILL.md

state-machine.SKILL.md
name: state-machine
description: "Generic state machine patterns — IState interface, StateMachine<T>, game state management (menu/gameplay/pause), enemy AI states, hierarchical FSM. Load when implementing state-driven behavior."
globs: ["**/State*.cs", "**/FSM*.cs", "**/*Machine*.cs"]

State Machine Patterns

A generic, reusable finite state machine for Unity. Covers player states, enemy AI, game flow (menu/gameplay/pause), hierarchical FSMs, and ScriptableObject-driven states for designer configuration.

IState Interface

The contract every state must fulfill. Keep it minimal: enter, exit, tick, and physics tick.

public interface IState
{
    /// <summary>Called once when entering this state.</summary>
    void Enter();

    /// <summary>Called once when leaving this state.</summary>
    void Exit();

    /// <summary>Called every frame while this state is active.</summary>
    void Update();

    /// <summary>Called every fixed timestep while this state is active.</summary>
    void FixedUpdate();
}

If your game does not need `FixedUpdate` in states (e.g., turn-based game), drop it from the interface. Keep the interface as lean as your project requires.

---

StateMachine Generic Class

A generic state machine that can be used with any state type. The type parameter `T` is typically the owner (player, enemy, game manager) so states can access it.

using System;
using System.Collections.Generic;
using UnityEngine;

public class StateMachine<T>
{
    public IState CurrentState { get; private set; }
    public IState PreviousState { get; private set; }

    private T _owner;
    private Dictionary<Type, IState> _states = new();

    public StateMachine(T owner)
    {
        _owner = owner;
    }

    /// <summary>
    /// Register a state instance. Call during initialization.
    /// </summary>
    public void AddState(IState state)
    {
        _states[state.GetType()] = state;
    }

    /// <summary>
    /// Transition to a new state by type. Calls Exit on current, Enter on new.
    /// </summary>
    public void ChangeState<TState>() where TState : IState
    {
        var type = typeof(TState);

        if (!_states.TryGetValue(type, out var newState))
        {
            Debug.LogError($"State {type.Name} not registered in state machine.");
            return;
        }

        if (CurrentState == newState) return; // Already in this state

        PreviousState = CurrentState;
        CurrentState?.Exit();
        CurrentState = newState;
        CurrentState.Enter();
    }

    /// <summary>
    /// Change state by instance (useful when states are not unique by type,
    /// e.g., ScriptableObject states).
    /// </summary>
    public void ChangeState(IState newState)
    {
        if (newState == null || CurrentState == newState) return;

        PreviousState = CurrentState;
        CurrentState?.Exit();
        CurrentState = newState;
        CurrentState.Enter();
    }

    /// <summary>
    /// Return to the previous state.
    /// </summary>
    public void RevertToPreviousState()
    {
        if (PreviousState != null)
            ChangeState(PreviousState);
    }

    /// <summary>
    /// Call from the owner's Update().
    /// </summary>
    public void Update()
    {
        CurrentState?.Update();
    }

    /// <summary>
    /// Call from the owner's FixedUpdate().
    /// </summary>
    public void FixedUpdate()
    {
        CurrentState?.FixedUpdate();
    }

    /// <summary>
    /// Check if the current state is of a given type.
    /// </summary>
    public bool IsInState<TState>() where TState : IState
    {
        return CurrentState is TState;
    }

    public T Owner => _owner;
}

---

Player State Example

A concrete example: player states for a 2D platformer. Each state is a class that holds a reference to the player controller.

Base Player State

public abstract class PlayerState : IState
{
    protected PlayerController Player { get; }
    protected StateMachine<PlayerController> StateMachine { get; }

    protected PlayerState(PlayerController player, StateMachine<PlayerController> stateMachine)
    {
        Player = player;
        StateMachine = stateMachine;
    }

    public virtual void Enter() { }
    public virtual void Exit() { }
    public virtual void Update() { }
    public virtual void FixedUpdate() { }
}

Idle State

public class PlayerIdleState : PlayerState
{
    public PlayerIdleState(PlayerController player, StateMachine<PlayerController> sm)
        : base(player, sm) { }

    public override void Enter()
    {
        Player.Animator.Play("Idle");
        Player.Rb.velocity = new Vector2(0f, Player.Rb.velocity.y);
    }

    public override void Update()
    {
        if (!Player.IsGrounded)
        {
            StateMachine.ChangeState<PlayerFallState>();
            return;
        }

        if (Player.JumpRequested)
        {
            StateMachine.ChangeState<PlayerJumpState>();
            return;
        }

        if (Mathf.Abs(Player.MoveInput.x) > 0.1f)
        {
            StateMachine.ChangeState<PlayerRunState>();
            return;
        }

        if (Player.DashRequested)
        {
            StateMachine.ChangeState<PlayerDashState>();
            return;
        }
    }
}

Jump State

public class PlayerJumpState : PlayerState
{
    public PlayerJumpState(PlayerController player, StateMachine<PlayerController> sm)
        : base(player, sm) { }

    public override void Enter()
    {
        Player.Animator.Play("Jump");
        Player.ExecuteJump();
    }

    public override void Update()
    {
        // Transition to fall when velocity turns downward
        if (Player.Rb.velocity.y <= 0f)
        {
            StateMachine.ChangeState<PlayerFallState>();
            return;
        }

        // Variable jump height: cut velocity on release
        if (Player.JumpReleased && Player.Rb.velocity.y
Read more
Ships witheverything-claude-unity

The ultimate Claude Code toolkit for Unity game development. A production-ready, plug-and-play system that gives Claude Code deep Unity expertise — from writing performant C# to building scenes, profiling performance, and triggering iOS/Android builds — all

Get the whole plugin

Other skills on everything-claude-unity.