Menu
CoddyTech

Intelligenze dei nemici

Fa parte della sezione Architettura dei giochi in Unity del percorso Unity di Coddy. Lezione 31 di 50.

Il cervello di un nemico è una macchina a stati con uno stato per ogni comportamento. Questo scheletro cammina tra i suoi posti di guardia, insegue un giocatore che si avvicina entro 6 unità e sferra un colpo di spada al secondo quando è vicino. Ogni stato decide da sé come uscirne, e lo scheletro mantiene gli helper che condividono:

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

Gli stati vengono creati una sola volta e restano in vita quanto lo scheletro, quindi i loro campi persistono tra una visita e l'altra. next di PatrolState mantiene il suo valore anche dopo un inseguimento, e lo scheletro continua a camminare verso il posto di guardia che stava raggiungendo. Enter reimposta solo ciò che deve ricominciare da capo: AttackState imposta cooldown a 0, così il primo colpo arriva appena lo scheletro raggiunge il giocatore.

Tutti i movimenti passano attraverso WalkTo, qui MoveTowards sul transform, che fa camminare attraverso i muri. Per muovere lo scheletro con un Rigidbody, invece, WalkTo imposta la velocità del corpo e lo scheletro aggiorna la macchina in FixedUpdate, dove Time.deltaTime è il passo della fisica. I tre stati non cambiano: indicano dove andare, il proprietario indica come.

challenge icon

Sfida

Medio

Un cavaliere fa la guardia al cortile del castello. Le frecce guidano il Player, che ha Health con TakeDamage(int amount) (entrambi già pronti). Knight.cs contiene i campi che l’Inspector compila (waypoints da W0 a W2, player, playerHealth, speed 3 e gli intervalli indicati sotto) e i metodi di supporto che usano il suo Rigidbody: DistanceTo(point) e PlayerDistance() misurano la distanza sul terreno, WalkTo(target) cammina verso un punto, Stop() resta fermo. Dagli un cervello:

  • In Knight.cs, crea la macchina e i tre stati (campi patrol, chase e attack), avvia il pattugliamento e aggiorna la macchina in FixedUpdate.
  • In KnightStates.cs, scrivi PatrolState, ChaseState e AttackState, ognuno dei quali riceve il cavaliere nel costruttore.
  • Pattugliamento: cammina verso waypoints[next]; quando è a meno di 0.3 da esso, dirigiti verso il successivo e, dopo l’ultimo, torna al primo. Se il giocatore è più vicino di sightRange (5), inseguilo. Dopo un inseguimento, la pattuglia riprende verso il waypoint che stava raggiungendo.
  • Inseguimento: cammina verso il giocatore. Se è più vicino di attackRange (1.5), attacca. Se è più lontano di loseRange (8), torna a pattugliare. Tra 5 e 8 l’inseguimento continua, così il cavaliere non passa continuamente da uno stato all’altro al limite del suo campo visivo.
  • Attacco: resta fermo e colpisci il giocatore subito per 1 danno, poi ogni secondo, finché si trova entro attackRange; quando è più lontano, torna a inseguirlo.

Premi Play, lascia che il cavaliere ti veda, subisci un colpo, poi scappa e infine premi Check.

Provalo tu

using UnityEngine;

// PatrolState, ChaseState e AttackState
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Architettura dei giochi in Unity