Menu
CoddyTech

Cérebros dos inimigos

Parte da seção Arquitetura de Jogos no Unity do Journey de Unity da Coddy. Lição 39 de 64.

O cérebro de um inimigo é uma máquina de estados com um estado para cada comportamento. Este esqueleto caminha entre seus postos, persegue um jogador que chega a menos de 6 unidades e golpeia com a espada uma vez por segundo quando está perto. Cada estado decide sua própria saída, e o esqueleto mantém os auxiliares que eles compartilham:

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; }
    }
}

Os estados são criados uma vez e existem enquanto o esqueleto existir, então seus campos persistem entre as visitas. O next de PatrolState continua definido após uma perseguição, e o esqueleto continua caminhando até o posto para onde estava indo. Enter redefine apenas o que deve começar de novo: o de AttackState define cooldown como 0, então o primeiro golpe acontece assim que o esqueleto alcança o jogador.

Toda a movimentação passa por WalkTo, que aqui usa MoveTowards no transform, atravessando paredes. Para mover o esqueleto com um Rigidbody, em vez disso, WalkTo define a velocidade do corpo e o esqueleto atualiza a máquina em FixedUpdate, onde Time.deltaTime é o passo da física. Os três estados não mudam: eles dizem para onde ir, o objeto proprietário diz como.

challenge icon

Desafio

Médio

Dê ao cavaleiro os estados PatrolState e ChaseState em KnightStates.cs, passando o cavaleiro para cada um deles.

  1. Patrulha: caminhe até waypoints[next]; quando estiver a menos de 0.3, avance next, voltando ao início ao chegar ao fim, e mantenha seu valor entre as visitas. Se estiver mais perto que sightRange, persiga.
  2. Perseguição: caminhe até o jogador; se estiver mais longe que loseRange, patrulhe.
  3. Em Knight, crie a máquina e os estados em Awake, inicie a patrulha em Start e atualize a máquina em FixedUpdate.

Pressione “Jogar”, depois aproxime-se e corra. Em seguida, pressione “Verificar”.

Experimente você mesmo

using UnityEngine;

// PatrolState e ChaseState

Todas as lições de Arquitetura de Jogos no Unity

Pratique por conta própria: Playground de Unity