Menu
CoddyTech

Estados como clases

Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 28 de 50.

El cambio de estado basado en un enum de la sección 3 concentra el trabajo de todos los estados en un solo Update. Eso deja de ser escalable cuando los estados tienen datos propios: un temporizador que solo usa un estado acaba como campo de MonoBehaviour, junto a los campos de todos los demás estados, y cada caso debe recordar restablecer lo que usa. El patrón de estados de C# da a cada estado su propia clase, y cada clase implementa una interfaz. Esta baliza parpadea o permanece encendida, y la barra espaciadora alterna entre los dos estados:

public interface IState
{
    void Enter();
    void Tick();
    void Exit();
}

public class BlinkState : IState
{
    private Renderer lamp;
    private float timer;

    public BlinkState(Renderer lamp)
    {
        this.lamp = lamp;
    }

    public void Enter() { timer = 0f; }

    public void Tick()
    {
        timer += Time.deltaTime;
        if (timer >= 0.5f)
        {
            timer = 0f;
            lamp.enabled = !lamp.enabled;
        }
    }

    public void Exit() { lamp.enabled = true; }
}

public class SteadyState : IState
{
    public void Enter() { }
    public void Tick() { }
    public void Exit() { }
}

public class Beacon : MonoBehaviour
{
    public Renderer lamp;
    private IState blink;
    private IState steady;
    private IState current;

    void Start()
    {
        blink = new BlinkState(lamp);
        steady = new SteadyState();
        SetState(steady);
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame) SetState(current == steady ? blink : steady);
        current.Tick();
    }

    void SetState(IState next)
    {
        if (current != null) current.Exit();
        current = next;
        current.Enter();
    }
}

Los estados son clases de C# simples, no MonoBehaviours. Los creas con new y les pasas lo que necesitan a través del constructor, en este caso el Renderer de la lámpara, porque no son componentes y no pueden llamar a GetComponent ni mostrar campos en el Inspector. Unity tampoco llama a sus métodos: Beacon es el MonoBehaviour, así que su Update llama a current.Tick() en cada fotograma.

El timer pertenece únicamente a BlinkState, y su Enter lo establece en 0 cada vez que la baliza empieza a parpadear. Exit hace la limpieza cuando termina el estado: la barra espaciadora puede pulsarse mientras la lámpara está apagada, y Exit vuelve a encenderla, para que SteadyState nunca empiece con la lámpara apagada. SetState ejecuta el Exit del estado anterior y luego el Enter del nuevo estado. Un tercer estado, como un pulso lento, sería una clase más, y el Update de Beacon no cambiaría.

challenge icon

Desafío

Intermedio

Una torreta centinela protege el patio. Las flechas mueven al Player (listo). Dale a la torreta dos estados, escritos como clases:

  • En IState.cs, declara public interface IState con void Enter(), void Tick() y void Exit().
  • En TurretStates.cs, escribe dos clases simples que lo implementen. ScanState recibe la cabeza de la torreta en su constructor. Barre la cabeza de lado a lado: el ángulo y local de la cabeza se mueve a 90 grados por segundo entre -45 y 45, comenzando desde 0 y girando hacia arriba cada vez que comienza el escaneo. Su Enter también colorea la cabeza con Color.green.
  • AlertState recibe la cabeza y al jugador. Su Enter colorea la cabeza con Color.red y registra Intruder!; su Tick gira la cabeza para mirar al jugador solo alrededor del eje y, sin inclinación; su Exit registra All clear.
  • En Turret.cs, crea ambos estados en Start y comienza a escanear. En cada fotograma, cambia al estado de alerta cuando el jugador está más cerca que range (4) de la torreta, y vuelve al escaneo cuando no lo está; después ejecuta el Tick del estado actual. Un cambio ejecuta el Exit del estado anterior y luego el Enter del nuevo estado.

Pulsa Play, acércate a la torreta y vuelve a alejarte; después pulsa Check.

Pruébalo tú mismo

using UnityEngine;

// ScanState y AlertState
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Arquitectura de juegos en Unity