Receber por email
← Voltar para o catálogo

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.

20estrelas
Atualizado há 6 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add XeldarAlz/everything-claude-unity

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/state-machine/svg)](https://www.skillteca.com.br/skills/state-machine)
#ai

Skills relacionadas

Ver todas de Marketing →

Alerta por categoria

Receba novas skills de Marketing toda segunda

1 email curto, só com as skills novas de Marketing. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

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 > 0f)
        {
            Player.CutJumpShort();
        }

        // Allow wall slide if touching wall
        if (Player.IsTouchingWall && !Player.IsGrounded)
        {
            StateMachine.ChangeState<PlayerWallSlideState>();
            return;
        }
    }

    public override void FixedUpdate()
    {
        Player.ApplyHorizontalMovement();
    }
}

Wiring It Up in the Player Controller

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    // Public properties that states read
    public Rigidbody2D Rb { get; private set; }
    public Animator Animator { get; private set; }
    public Vector2 MoveInput { get; private set; }
    public bool IsGrounded { get; private set; }
    public bool IsTouchingWall { get; private set; }
    public bool JumpRequested { get; set; }
    public bool JumpReleased { get; set; }
    public bool DashRequested { get; set; }

    private StateMachine<PlayerController> _stateMachine;

    private void Awake()
    {
        Rb = GetComponent<Rigidbody2D>();
        Animator = GetComponent<Animator>();

        _stateMachine = new StateMachine<PlayerController>(this);
        _stateMachine.AddState(new PlayerIdleState(this, _stateMachine));
        _stateMachine.AddState(new PlayerRunState(this, _stateMachine));
        _stateMachine.AddState(new PlayerJumpState(this, _stateMachine));
        _stateMachine.AddState(new PlayerFallState(this, _stateMachine));
        _stateMachine.AddState(new PlayerWallSlideState(this, _stateMachine));
        _stateMachine.AddState(new PlayerDashState(this, _stateMachine));

        _stateMachine.ChangeState<PlayerIdleState>();
    }

    private void Update()
    {
        ReadInput();
        CheckGround();
        CheckWall();
        _stateMachine.Update();
    }

    private void FixedUpdate()
    {
        _stateMachine.FixedUpdate();
    }

    // Movement methods called by states
    public void ExecuteJump() { /* see character-controller skill */ }
    public void CutJumpShort() { /* see character-controller skill */ }
    public void ApplyHorizontalMovement() { /* see character-controller skill */ }

    private void ReadInput() { /* read from Input System */ }
    private void CheckGround() { /* overlap circle check */ }
    private
Compartilhar X LinkedIn