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.
Desafío
IntermedioUna torreta centinela protege el patio. Las flechas mueven al Player (listo). Dale a la torreta dos estados, escritos como clases:
- En
IState.cs, declarapublic interface IStateconvoid Enter(),void Tick()yvoid Exit(). - En
TurretStates.cs, escribe dos clases simples que lo implementen.ScanStaterecibe 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-45y45, comenzando desde 0 y girando hacia arriba cada vez que comienza el escaneo. Su Enter también colorea la cabeza conColor.green. AlertStaterecibe la cabeza y al jugador. Su Enter colorea la cabeza conColor.redy registraIntruder!; su Tick gira la cabeza para mirar al jugador solo alrededor del eje y, sin inclinación; su Exit registraAll 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 querange(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
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
1Componentes, no jerarquías
Componentes pequeñosUn script base para enemigosComponentes abstractosComponentes que trabajan juntosRepaso: torreta modular4Datos serializados
Clases serializablesListas en el InspectorEnumeraciones en el InspectorRepaso: tabla de botín7Máquinas de estados
Estados como clasesUna máquina de estadosTransicionesCerebros de enemigosRepaso: estados de puertas10Proyecto: Superviviente de la arena
El héroeTipos de enemigos2Interfaces en Unity
IDamageableInterfaces y TryGetComponentGetComponentsRepaso: tecla de interacción5ScriptableObjects
Recursos de datosEstadísticas de armasConfiguración compartidaOleadas como datosRepaso: base de datos de objetos