Menu
CoddyTech

Gegner-KI

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 39 von 64.

Das Gehirn eines Gegners ist eine Zustandsmaschine mit einem Zustand pro Verhalten. Dieses Skelett läuft zwischen seinen Posten hin und her, verfolgt einen Spieler, der sich ihm auf weniger als 6 Einheiten nähert, und schwingt einmal pro Sekunde mit seinem Schwert, wenn es nahe genug ist. Jeder Zustand entscheidet selbst, wie er verlassen wird, und das Skelett behält die Helfer, die sie gemeinsam verwenden:

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

Die Zustände werden einmal erstellt und bleiben so lange bestehen wie das Skelett, daher bleiben ihre Felder zwischen den Besuchen erhalten. next von PatrolState ist auch nach einer Verfolgung noch gesetzt, und das Skelett läuft weiter zu dem Posten, auf den es zuging. Enter setzt nur zurück, was neu beginnen soll: Das Enter von AttackState setzt cooldown auf 0, sodass der erste Schwerthieb erfolgt, sobald das Skelett den Spieler erreicht.

Die gesamte Bewegung läuft über WalkTo, hier MoveTowards auf dem Transform, wodurch das Skelett durch Wände läuft. Um das Skelett stattdessen mit einem Rigidbody zu bewegen, setzt WalkTo die Geschwindigkeit des Körpers, und das Skelett aktualisiert die Maschine in FixedUpdate, wo Time.deltaTime dem Physik-Zeitschritt entspricht. Die drei Zustände ändern sich nicht: Sie geben an, wohin es gehen soll, der Besitzer gibt an, wie.

challenge icon

Aufgabe

Mittel

Gib dem Ritter in KnightStates.cs die Zustände PatrolState und ChaseState, denen jeweils der Ritter übergeben wird.

  1. Patrouille: Gehe zu waypoints[next]; wenn du näher als 0.3 bist, erhöhe next zyklisch und behalte den Wert zwischen den Besuchen bei. Wenn du näher als sightRange bist, verfolge den Spieler.
  2. Verfolgung: Gehe zum Spieler; wenn du weiter als loseRange entfernt bist, patrouilliere.
  3. Erstelle in Knight die Zustandsmaschine und die Zustände in Awake, starte mit der Patrouille in Start und rufe Tick in FixedUpdate auf.

Drücke „Spielen“, nähere dich dann und renne los. Drücke danach „Prüfen“.

Probier es selbst

using UnityEngine;

// PatrolState und ChaseState

Alle Lektionen in Spielarchitektur in Unity

Übe selbstständig: Unity-Playground