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.
Görev
OrtaBir şö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.csiçinde makineyi ve üç durumu (patrol,chaseveattackalanları) oluştur, devriye gezmeye başlat ve makineyi FixedUpdate içinde çalıştır.KnightStates.csiçinde, her biri kurucusunda şövalyeyi alanPatrolState,ChaseStateveAttackStatesı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. OyuncusightRange(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
attackRangeiç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
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
1Hiyerarşiler Değil, Bileşenler
Küçük BileşenlerTemel Bir Düşman BetiğiSoyut BileşenlerBirlikte Çalışan BileşenlerÖzet: Modüler Taret4Serileştirilmiş Veriler
Serileştirilebilir SınıflarInspector'da ListelerInspector'da Enum'larÖzet: Ganimet Tablosu7Durum Makineleri
Sınıflar Olarak DurumlarBir Durum MakinesiGeçişlerDüşmanların Yapay ZekâsıTekrar: Kapı Durumları10Proje: Arena Hayatta Kalma
KahramanDüşman Türleri5ScriptableObjects
Veri VarlıklarıSilah İstatistikleriPaylaşılan AyarlarVeri Olarak DalgalarTekrar: Eşya Veritabanı8Yeniden Kullanılabilir Kod
Genişletme MetotlarıGeneric SingletonGeneric YardımcılarTekrar: FindNearest