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.
Görev
OrtaKnightStates.cs içinde şövalyeye PatrolState ve ChaseState ver; her birine şövalyeyi ver.
- Devriye:
waypoints[next]konumuna yürü;0.3mesafe içine girince döngü oluşturaraknextdeğerini ilerlet ve ziyaretler arasında değerini koru.sightRangemesafesinden daha yakına gelince kovala. - Kovalamaca: oyuncuya doğru yürü;
loseRangemesafesinden daha uzağa gidince devriye gez. Knightiç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
1Kalıtım Değil, Bileşenler
Küçük BileşenlerTemel Düşman Script'iSoyut BileşenlerBirlikte Çalışan BileşenlerTekrar: Modüler TaretTekrar: Çift Namlulu Top4Serileştirilmiş Veriler
Serileştirilebilir SınıflarInspector'da ListelerInspector'da Enum'larTekrar: Ganimet TablosuTekrar: Ganimeti At7Durum Makineleri
Sınıflar Olarak DurumlarAlarm DurumuBir Durum MakinesiGeçişlerDüşmanların Yapay ZekâsıŞövalye SaldırıyorÖzet: Kapı Durumları2Unity'de Arayüzler
IDamageableArayüzler ve TryGetComponentGetComponentsÖzet: Etkileşim TuşuÖzet: Erişim Mesafesindeki En Yakın5ScriptableObjects
Veri VarlıklarıSilah İstatistikleriOrtak AyarlarRüzgârı KaydetVeri Olarak DalgalarTekrar: Eşya VeritabanıTekrar: Dükkândan Satın Al8Yeniden Kullanılabilir Kod
Genişletme MetotlarıGeneric SingletonGeneric YardımcılarTekrar: FindNearestKendi başına pratik yap: Unity playground