Menu
CoddyTech

Mózgi przeciwników

Część sekcji Architektura gier w Unity ścieżki Unity w Coddy. Lekcja 39 z 64.

Mózg przeciwnika to maszyna stanów, w której każdemu zachowaniu odpowiada jeden stan. Ten szkielet chodzi między swoimi posterunkami, rusza w pościg za graczem, który zbliży się na odległość 6 jednostek, i co sekundę wymachuje mieczem, gdy jest blisko. Każdy stan sam decyduje, kiedy go opuścić, a szkielet udostępnia pomocnicze elementy wspólne dla wszystkich stanów:

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

Stany są tworzone raz i istnieją tak długo jak szkielet, więc ich pola zachowują wartości między kolejnymi wejściami do stanu. next w PatrolState nadal ma ustawioną wartość po pościgu, a szkielet idzie dalej do posterunku, do którego zmierzał. Enter resetuje tylko to, co powinno zacząć się od nowa: Enter w AttackState ustawia cooldown na 0, więc pierwszy zamach następuje, gdy tylko szkielet dotrze do gracza.

Cały ruch odbywa się przez WalkTo, które tutaj wykorzystuje MoveTowards na transformie — ta metoda pozwala przechodzić przez ściany. Aby zamiast tego poruszać szkieletem za pomocą Rigidbody, WalkTo ustawia prędkość ciała, a szkielet wykonuje Tick maszyny w FixedUpdate, gdzie Time.deltaTime oznacza krok fizyki. Trzy stany pozostają bez zmian: określają, dokąd iść, a właściciel określa, jak to zrobić.

challenge icon

Wyzwanie

Średni

Dodaj do rycerza PatrolState i ChaseState w pliku KnightStates.cs, przekazując rycerza do każdej z nich.

  1. Patrol: idź do waypoints[next]; gdy odległość będzie mniejsza niż 0.3, przejdź do następnego elementu next, zawracając na początku i zachowując go między odwiedzinami. Gdy odległość będzie mniejsza niż sightRange, rozpocznij pościg.
  2. Pościg: idź do gracza; gdy odległość będzie większa niż loseRange, wróć do patrolowania.
  3. W Knight utwórz maszynę stanów i stany w Awake, rozpocznij patrol w Start, a w FixedUpdate wykonuj tick.

Naciśnij „Graj”, a następnie podejdź blisko i uciekaj. Potem naciśnij „Sprawdź”.

Spróbuj swoich sił

using UnityEngine;

// PatrolState i ChaseState

Wszystkie lekcje w sekcji Architektura gier w Unity

Poćwicz samodzielnie: Edytor online Unity