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 31 / 50.

Bir düşmanın beyni, her davranış için bir durumu olan bir durum makinesidir. Bu iskelet, devriye noktaları arasında yürür, 6 birim yakınına gelen bir oyuncuyu kovalar ve yakındayken saniyede bir kez kılıcını savurur. Her durum kendi çıkış yoluna karar verir ve iskelet, durumların paylaştığı yardımcıları korur:

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ı ziyaretler arasında korunur. PatrolState içindeki next, kovalamadan sonra da ayarlı kalır ve iskelet, yöneldiği devriye noktasına doğru yürümeye devam eder. Enter yalnızca yeniden başlaması gereken değerleri sıfırlar: AttackState içindeki kod, cooldown değerini 0 yapar; böylece iskelet oyuncuya ulaşır ulaşmaz ilk kılıç savuruşu 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 durum makinesini FixedUpdate içinde çalıştırır; burada Time.deltaTime fizik adımının süresidir. Üç durum değişmez: nereye gidileceğini onlar söyler, nasıl gidileceğini ise sahibi belirler.

challenge icon

Görev

Orta

Bir şövalye kale avlusunu koruyor. Ok tuşları, Health bileşeninde TakeDamage(int amount) bulunan Oyuncuyu hareket ettirir (ikisi de hazır). Knight.cs dosyasında, Inspector'ın doldurduğu alanlar (waypoints W0'dan W2'ye, player, playerHealth, speed 3 ve aşağıdaki menziller) ile Rigidbody'sini kullanan yardımcı işlevler bulunur: DistanceTo(point) ve PlayerDistance() yerdeki mesafeyi ölçer, WalkTo(target) bir noktaya doğru yürür, Stop() olduğu yerde durur. Ona bir beyin ver:

  • Knight.cs içinde makineyi ve üç durumu (patrol, chase ve attack alanları) oluştur, devriye gezmeye başlat ve makineyi FixedUpdate içinde çalıştır.
  • KnightStates.cs içinde, her biri kurucusunda şövalyeyi alan PatrolState, ChaseState ve AttackState sınıflarını yaz.
  • Devriye: waypoints[next] noktasına yürü; ona 0.3 mesafeden daha yakınken bir sonrakine yönel ve son noktadan sonra ilkine dön. Oyuncu sightRange (5) menzilinden daha yakınsa kovalanır. Kovalamadan sonra devriye, yöneldiği ara noktaya doğru devam eder.
  • Kovalama: Oyuncuya doğru yürü. attackRange (1.5) menzilinden daha yakınsa saldır. loseRange (8) menzilinden daha uzaksa devriyeye dön. 5 ile 8 arasında kovalama sürer; böylece şövalye görüş menzilinin sınırında iki durum arasında gidip gelmez.
  • Saldırı: Oldukları yerde dur ve attackRange içindeyken oyuncuya hemen 1 hasar ver, ardından her saniye tekrar vur; daha uzağa gittiklerinde yeniden kovala.

Play'e bas, şövalyenin seni görmesini sağla, bir darbe al, ardından kaç ve Check'e bas.

Kendin dene

using UnityEngine;

// PatrolState, ChaseState ve AttackState
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

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