Menu
CoddyTech

Düşmanların Yapay Zekâsı

Coddy'nin Unity Journey'sinin Unity'de Oyun Mimarisi bölümünün bir parçası. Ders 39 / 64.

Bir düşmanın beyni, her davranış için bir durum içeren bir durum makinesidir. Bu iskelet, devriye noktaları arasında yürür, 6 birim yakınına gelen oyuncuyu kovalar ve yaklaştığında saniyede bir kılıcını savurur. Her durum, kendisinden çıkış yolunu belirler ve iskelet, durumların paylaştığı yardımcıları kullanır:

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

Durumlar bir kez oluşturulur ve iskelet yaşadığı sürece varlığını sürdürür; bu nedenle alanları, duruma tekrar girildiğinde de değerlerini korur. PatrolState'in next alanı kovalamadan sonra da aynı değerde kalır ve iskelet, gitmekte olduğu devriye noktasına doğru yürümeye devam eder. Enter yalnızca sıfırlanması gereken değerleri sıfırlar: AttackState'in cooldown değerini 0 yapar, böylece iskelet oyuncuya ulaşır ulaşmaz ilk savuruş gerçekleşir.

Tüm hareketler WalkTo üzerinden yapılır; burada transform üzerinde MoveTowards kullanılır ve bu yöntem duvarların içinden geçer. İskeleti bunun yerine bir Rigidbody ile hareket ettirmek için WalkTo, gövdenin hızını ayarlar ve iskelet makineyi FixedUpdate içinde çalıştırır; burada Time.deltaTime fizik adımını ifade eder. Üç durum değişmez: nereye gidileceğini söylerler, sahibi ise nasıl gidileceğini belirler.

challenge icon

Görev

Orta

KnightStates.cs içinde şövalyeye PatrolState ve ChaseState ver; her birine şövalyeyi ver.

  1. Devriye: waypoints[next] konumuna yürü; 0.3 mesafe içine girince döngü oluşturarak next değerini ilerlet ve ziyaretler arasında değerini koru. sightRange mesafesinden daha yakına gelince kovala.
  2. Kovalamaca: oyuncuya doğru yürü; loseRange mesafesinden daha uzağa gidince devriye gez.
  3. Knight içinde makineyi ve durumları Awake'te oluştur, Start'ta devriyeyi başlat, FixedUpdate'te tick çağır.

“Oyna” düğmesine bas, sonra yaklaşıp kaç. Ardından “Kontrol et” düğmesine bas.

Kendin dene

using UnityEngine;

// PatrolState ve ChaseState

Unity'de Oyun Mimarisi bölümündeki tüm dersler

Kendi başına pratik yap: Unity playground