Una máquina de estados
Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 29 de 50.
El método SetState del faro sería igual en todos los objetos con estados: una torreta, un enemigo, una puerta. Ese código puede estar en su propia clase, una máquina de estados, que mantiene el estado actual y lo cambia. Cada objeto crea una máquina y la llama, en lugar de repetir el código:
public class StateMachine
{
public IState Current { get; private set; }
public void ChangeState(IState next)
{
Current?.Exit();
Current = next;
Current.Enter();
}
public void Tick()
{
Current?.Tick();
}
}
public class Beacon : MonoBehaviour
{
public Renderer lamp;
private StateMachine machine = new StateMachine();
private IState blink;
private IState steady;
void Start()
{
blink = new BlinkState(lamp);
steady = new SteadyState();
machine.ChangeState(steady);
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame) machine.ChangeState(machine.Current == steady ? blink : steady);
machine.Tick();
}
}El primer ChangeState no tiene ningún estado del que salir: Current es null, y ?. omite la llamada a Exit. La sección 1 advertía que ?. no detecta el falso null de Unity; eso se refiere a los objetos de Unity destruidos, y los estados son objetos C# normales, así que ?. es seguro aquí. Current tiene un private set, así que ningún script puede cambiar el estado sin pasar por ChangeState y sus métodos Exit y Enter.
El orden dentro de ChangeState importa siempre que dos estados afecten al mismo objeto. Exit deshace lo que cambió el estado anterior y, después, Enter configura el nuevo, así que el nuevo estado tiene la última palabra. Si el método Enter de un DarkState apagara la lámpara y se ejecutara antes que Exit de BlinkState, ese Exit volvería a encender la lámpara en el estado oscuro. StateMachine también es una clase normal: el faro, una torreta y un enemigo crean cada uno su propia instancia con new y llaman a su Tick desde su Update.
Desafío
IntermedioMantén presionada la barra espaciadora para moverte sigilosamente. WalkState y SneakState ya están listos en PlayerStates.cs: sus métodos Enter y Exit registran lo que sucede (Walk: enter, Sneak: exit...), y sus métodos Tick llaman a Move() del jugador. Escribe la máquina que los ejecuta.
- En
StateMachine.cs, escribe una clase simpleStateMachinecon una propiedad públicaCurrentque solo la máquina pueda establecer, un métodoChangeState(IState next)que ejecute Exit del estado anterior y después Enter del nuevo estado, y un métodoTick()que ejecute Tick del estado actual. - El jugador solicita su estado en cada fotograma, así que llamar a
ChangeStatecon el estado que ya es el actual no hace nada: ni Exit ni Enter. - En
Player.cs, añade un campoStateMachinellamadomachine. En Start, crea la máquina y ambos estados (cada uno recibe al jugador) y empieza caminando. En Update, cambia a moverse sigilosamente mientras se mantenga presionada la barra espaciadora y a caminar en caso contrario; después, actualiza la máquina.
Presiona Play, camina, mantén presionada la barra espaciadora y sigue caminando; luego, presiona Check.
Pruébalo tú mismo
// StateMachine: Current, ChangeState y Tick
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