Menu
CoddyTech

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.

challenge icon

Desafío

Intermedio

Asigna al caballero PatrolState y ChaseState en KnightStates.cs, pasando el caballero a cada uno.

  1. Patrulla: camina hasta waypoints[next]; cuando esté a menos de 0.3, avanza next, volviendo al principio al llegar al final, y conserva su valor entre visitas. Si está más cerca que sightRange, persíguelo.
  2. Persecución: camina hacia el jugador; si está más lejos que loseRange, patrulla.
  3. 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

Practica por tu cuenta: Playground de Unity