Cerebros enemigos
Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 39 de 64.
El cerebro de un enemigo es una máquina de estados con un estado por cada comportamiento. Este esqueleto camina entre sus puestos, persigue a un jugador que se acerca a menos de 6 unidades y blande su espada una vez por segundo cuando está cerca. Cada estado decide cómo salir de él, y el esqueleto conserva los métodos auxiliares que comparten:
public class Skeleton : MonoBehaviour
{
public Transform player;
public Transform[] posts;
public float speed = 2f;
public StateMachine machine = new StateMachine();
public IState patrol, chase, attack;
void Start()
{
patrol = new PatrolState(this);
chase = new ChaseState(this);
attack = new AttackState(this);
machine.ChangeState(patrol);
}
void Update() { machine.Tick(); }
public float PlayerDistance() { return Vector3.Distance(transform.position, player.position); }
public void WalkTo(Vector3 target)
{
target.y = transform.position.y;
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
public class PatrolState : IState
{
private Skeleton skel;
private int next;
public PatrolState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() < 6f) { skel.machine.ChangeState(skel.chase); return; }
Vector3 post = skel.posts[next].position;
post.y = skel.transform.position.y;
skel.WalkTo(post);
if (skel.transform.position == post) next = (next + 1) % skel.posts.Length;
}
}
public class ChaseState : IState
{
private Skeleton skel;
public ChaseState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
float d = skel.PlayerDistance();
if (d > 6f) { skel.machine.ChangeState(skel.patrol); return; }
if (d < 1.5f) { skel.machine.ChangeState(skel.attack); return; }
skel.WalkTo(skel.player.position);
}
}
public class AttackState : IState
{
private Skeleton skel;
private float cooldown;
public AttackState(Skeleton skel) { this.skel = skel; }
public void Enter() { cooldown = 0f; }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() > 1.5f) { skel.machine.ChangeState(skel.chase); return; }
cooldown -= Time.deltaTime;
if (cooldown <= 0f) { Debug.Log("Swing!"); cooldown = 1f; }
}
}Los estados se crean una sola vez y viven tanto como el esqueleto, así que sus campos se conservan entre visitas. El next de PatrolState sigue teniendo el mismo valor después de una persecución, y el esqueleto continúa caminando hacia el puesto al que se dirigía. Enter restablece solo lo que debe empezar de nuevo: el Enter de AttackState establece cooldown en 0, así que el primer golpe se produce en cuanto el esqueleto alcanza al jugador.
Todo el movimiento pasa por WalkTo, que aquí usa MoveTowards en el transform y atraviesa las paredes. Para mover el esqueleto con un Rigidbody, en cambio, WalkTo establece la velocidad del cuerpo y el esqueleto actualiza la máquina en FixedUpdate, donde Time.deltaTime corresponde al paso de física. Los tres estados no cambian: indican adónde ir; el propietario indica cómo.
Desafío
IntermedioAsigna al caballero PatrolState y ChaseState en KnightStates.cs, pasando el caballero a cada uno.
- Patrulla: camina hasta
waypoints[next]; cuando esté a menos de0.3, avanzanext, volviendo al principio al llegar al final, y conserva su valor entre visitas. Si está más cerca quesightRange, persíguelo. - Persecución: camina hacia el jugador; si está más lejos que
loseRange, patrulla. - En
Knight, crea la máquina y los estados en Awake, inicia la patrulla en Start y ejecuta Tick en FixedUpdate.
Pulsa «Jugar», acércate y corre. Después, pulsa «Comprobar».
Pruébalo tú mismo
using UnityEngine;
// PatrolState y ChaseState
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