Transiciones
Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 38 de 64.
¿Quién decide cuándo cambia el estado? Dejarlo en manos del objeto propietario vuelve a poner todas las reglas en un solo Update, como ocurría con el switch. La respuesta habitual es que cada estado conoce su propia salida: en su Tick comprueba la condición y le pide a la máquina el siguiente estado. Esta bomba espera hasta que el jugador se acerca, entonces enciende la mecha y vuelve a esperar si el jugador se aleja corriendo:
public class Bomb : MonoBehaviour
{
public Transform player;
public StateMachine machine = new StateMachine();
public IState idle;
public IState fuse;
void Start()
{
idle = new IdleState(this);
fuse = new FuseState(this);
machine.ChangeState(idle);
}
void Update() { machine.Tick(); }
public bool PlayerNear()
{
return Vector3.Distance(transform.position, player.position) < 3f;
}
}
public class IdleState : IState
{
private Bomb bomb;
public IdleState(Bomb bomb) { this.bomb = bomb; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
if (bomb.PlayerNear()) bomb.machine.ChangeState(bomb.fuse);
}
}
public class FuseState : IState
{
private Bomb bomb;
private float timer;
public FuseState(Bomb bomb) { this.bomb = bomb; }
public void Enter() { timer = 2f; }
public void Exit() { }
public void Tick()
{
if (!bomb.PlayerNear())
{
bomb.machine.ChangeState(bomb.idle);
return;
}
timer -= Time.deltaTime;
if (timer <= 0f)
{
Debug.Log("Boom!");
Object.Destroy(bomb.gameObject);
}
}
}Cada estado recibe la bomba en su constructor y accede a la máquina, la comprobación del jugador y los demás estados a través de ella. La bomba crea cada estado una sola vez, en Start, así que un estado nunca crea otro con new: dos estados que se crearan mutuamente en sus constructores entrarían en un bucle hasta que se desbordara la pila. El Update de la bomba solo actualiza la máquina, y las reglas están en los estados a los que pertenecen: la mecha de 2 segundos es responsabilidad exclusiva de FuseState.
ChangeState ejecuta Exit de FuseState y Enter de IdleState de inmediato, pero el resto del Tick de FuseState seguiría ejecutándose después de la llamada. return lo detiene; de lo contrario, la mecha ardería un fotograma más aunque el estado ya hubiera terminado. Destroy se escribe Object.Destroy: un MonoBehaviour lo hereda de la clase Object de Unity, y una clase normal tiene que indicar el nombre de la clase.
Desafío
IntermedioEscribe las transiciones de la atrapamoscas en cada Tick de FlytrapStates.cs.
- Abierta: cuando
trap.PlayerInReach(), llama atrap.machine.ChangeState(trap.snap);. - Chasquido: suma
Time.deltaTimeatimer; al llegar a0.5, cambia atrap.chewsi el jugador todavía está al alcance; de lo contrario, atrap.open. - Masticar: cuenta
timerregresivamente desde 3; al llegar a 0, cambia atrap.open.
Presiona «Jugar», camina hacia la trampa y luego esquívala. Después, «Comprobar».
Pruébalo tú mismo
using UnityEngine;
public class OpenState : IState
{
private Flytrap trap;
public OpenState(Flytrap trap)
{
this.trap = trap;
}
public void Enter()
{
trap.Paint(new Color(0.3f, 0.8f, 0.2f));
}
public void Tick()
{
// Cerrar de golpe cuando el jugador esté al alcance
}
public void Exit()
{
}
}
public class SnapState : IState
{
private Flytrap trap;
private float timer;
public SnapState(Flytrap trap)
{
this.trap = trap;
}
public void Enter()
{
timer = 0f;
trap.Paint(new Color(1f, 0.55f, 0.1f));
}
public void Tick()
{
// Después de 0.5 segundos: masticar si el jugador sigue al alcance; si no, abrir de nuevo
}
public void Exit()
{
}
}
public class ChewState : IState
{
private Flytrap trap;
private float timer;
public ChewState(Flytrap trap)
{
this.trap = trap;
}
public void Enter()
{
timer = 3f;
trap.Paint(new Color(0.5f, 0.05f, 0.1f));
Debug.Log("Chomp!");
}
public void Tick()
{
// Después de 3 segundos: abrir de nuevo
}
public void Exit()
{
}
}
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 modularRepaso: cañón doble4Datos serializados
Clases serializablesListas en el InspectorEnumeraciones en el InspectorRepaso: tabla de botínRepaso: sortear el botín7Máquinas de estados
Estados como clasesEl estado de alertaUna máquina de estadosTransicionesCerebros enemigosEl caballero atacaRepaso: estados de puertas2Interfaces en Unity
IDamageableInterfaces y TryGetComponentGetComponentsRepaso: Tecla de interacciónRepaso: El más cercano al alcance5ScriptableObjects
Activos de datosEstadísticas de armasConfiguración compartidaGuardar el vientoOleadas como datosRepaso: base de datos de objetosRepaso: comprar en la tienda3Eventos
Eventos de C# en UnitySuscribirse en OnEnableCampos UnityEventLos eventos controlan la interfazRepaso: ventana emergente de logrosRepaso: temporizador de la ventana emergentePractica por tu cuenta: Playground de Unity