Logika Musuh
Termasuk bagian Arsitektur Game di Unity dalam perjalanan Unity di Coddy. Pelajaran 31 dari 50.
Otak musuh adalah state machine dengan satu state untuk setiap perilaku. Kerangka ini berjalan di antara posnya, mengejar pemain yang mendekat hingga dalam jarak 6 unit, dan mengayunkan pedangnya sekali setiap detik saat berada dekat. Setiap state menentukan caranya sendiri untuk keluar, dan kerangka menyimpan helper yang digunakan bersama:
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; }
}
}State dibuat sekali dan tetap hidup selama kerangka ada, sehingga field-nya bertahan di antara kunjungan. next milik PatrolState tetap tersimpan setelah pengejaran, dan kerangka terus berjalan menuju pos yang sedang dituju. Enter hanya mereset hal yang memang perlu dimulai ulang: Enter milik AttackState mengatur cooldown ke 0, sehingga ayunan pertama terjadi segera setelah kerangka mencapai pemain.
Semua gerakan dilakukan melalui WalkTo, yang di sini menggunakan MoveTowards pada transform, sehingga kerangka berjalan menembus dinding. Untuk menggerakkan kerangka dengan Rigidbody, WalkTo mengatur velocity badan dan kerangka menjalankan machine dalam FixedUpdate, dengan Time.deltaTime sebagai langkah fisika. Ketiga state tidak berubah: mereka menentukan ke mana harus pergi, sedangkan pemiliknya menentukan caranya.
Tantangan
SedangSeorang ksatria menjaga halaman kastel. Tombol panah menggerakkan Player, yang memiliki Health dengan TakeDamage(int amount) (keduanya sudah tersedia). Knight.cs memiliki field yang diisi melalui Inspector (waypoints W0 hingga W2, player, playerHealth, speed 3, dan rentang di bawah), serta helper yang menggunakan Rigidbody-nya: DistanceTo(point) dan PlayerDistance() mengukur jarak di permukaan tanah, WalkTo(target) berjalan menuju titik, dan Stop() berhenti. Beri ksatria ini otak:
- Di
Knight.cs, buat machine dan tiga state (fieldpatrol,chase, danattack), mulai dengan berpatroli, lalu jalankan machine di FixedUpdate. - Di
KnightStates.cs, tulisPatrolState,ChaseState, danAttackState, masing-masing menerima ksatria dalam konstruktornya. - Patroli: berjalan menuju
waypoints[next]; saat jaraknya kurang dari 0.3, menuju waypoint berikutnya, dan setelah waypoint terakhir kembali ke waypoint pertama. Jika jaraknya lebih dekat daripadasightRange(5), kejar pemain. Setelah pengejaran, patroli berlanjut ke waypoint yang sedang dituju. - Mengejar: berjalan menuju pemain. Jika jaraknya lebih dekat daripada
attackRange(1.5), serang. Jika jaraknya lebih jauh daripadaloseRange(8), patroli. Di antara 5 dan 8, pengejaran berlanjut, sehingga ksatria tidak bolak-balik di batas jarak pandangnya. - Menyerang: diam dan langsung memberikan 1 damage kepada pemain, lalu menyerang setiap detik selama pemain berada dalam jarak
attackRange; saat jaraknya lebih jauh, kejar lagi.
Tekan Play, biarkan ksatria melihatmu, terima satu serangan, lalu lari, kemudian tekan Check.
Coba sendiri
using UnityEngine;
// PatrolState, ChaseState, dan AttackState
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Arsitektur Game di Unity
1Komponen, Bukan Hierarki
Komponen KecilSkrip Dasar MusuhKomponen AbstrakKomponen yang Bekerja SamaRingkasan: Turret Modular5ScriptableObjects
Aset DataStatistik SenjataPengaturan BersamaGelombang sebagai DataUlasan: database Item8Kode yang Dapat Digunakan Kembali
Extension methodSingleton GenerikHelper GenerikUlasan: FindNearest