Musuh AI: mengejar pemain tanpa Navigation2D dan menemukan jalur A *

Membuat game di mana musuh harus mengejar pemain? Semuanya dimulai dengan yang sederhana - kami membuat musuh berlari ke pemain. Tetapi apa yang terjadi jika itu di belakang pohon, atau di sekitar sudut dinding? Nah, sekarang musuh akan terlihat sangat bodoh - dia akan berlari ke suatu objek, meraba-raba. Tidak begitu bagus!

Untuk mengatasi masalah ini, Anda dapat menggunakan node Navigation2D atau AStar yang dibangun di Godot (di sini adalah tutorial GDQuest di kedua node ). Namun dalam Helms of Fury, kami menggunakan metode berbeda yang bekerja sangat baik untuk permainan kami, dan kami ingin membagikannya dalam tutorial ini. Begini tampilannya:


Mulai bekerja


Kami berasumsi bahwa Anda membuat musuh sebagai objek KinematicBody2D dan menggunakan mesin negara untuk mengontrol negara mereka. Tidak yakin apa itu mesin negara? Saya suka artikel ini menjelaskan mesin negara dan cara menggunakannya. Berikut ini artikel lain tentang penerapan mesin negara sederhana di Godot .

Mari kita mulai dengan keadaan Chase sederhana untuk musuh bodoh yang hanya berlari ke sasarannya dan terjebak di suatu tempat di sepanjang jalan:

# ChaseState.gd

func _init(enemy, params):
  enemy.dir = (enemy.target.position - enemy.position).normalized()

func _physics_process(delta):
  var motion = enemy.dir * enemy.speed
  enemy.move_and_slide(motion)

Jejak bau


Untuk meningkatkan status, kami akan memaksa pemain untuk meninggalkan jejak dari posisi sebelumnya saat bergerak. Berkat ini, ketika musuh tidak melihat pemain, dia akan memeriksa untuk melihat apakah ada posisi masa lalunya dapat dilihat, dan kemudian mengikuti mereka ke pemain. Karena ini mirip dengan bagaimana anjing mengambil jejak kaki, kita akan menyebutnya jejak bau.

Agar jejak bau berfungsi, kita perlu menambahkan simpul Timer ke pemain, mengaktifkannya untuk secara otomatis memulai dan mengatur wait_time (kami menggunakan 0,1), dan kemudian menambahkan kode sehingga pemain meninggalkan bau ketika hitungan mundur berakhir.

# Player.gd
extends KinematicBody2D

const scent_scene = preload("res://Player/Scent.tscn")

var scent_trail = []

func _ready():
  $ScentTimer.connect("timeout", self, "add_scent")

func add_scent():
  var scent      = scent_scene.instance()
  scent.player   = player
  scent.position = player.position

  Game.level.effects.add_child(scent)
  scent_trail.push_front(scent)

Maka Anda perlu menambahkan Scent.tscn yang ditinggalkan itu sendiri. Ini adalah adegan Node2D sederhana yang berisi Timer sehingga baunya kedaluwarsa.

# Player.gd
extends KinematicBody2D

const scent_scene = preload("res://Player/Scent.tscn")

var scent_trail = []

func _ready():
  $ScentTimer.connect("timeout", self, "add_scent")

func add_scent():
  var scent      = scent_scene.instance()
  scent.player   = player
  scent.position = player.position

  Game.level.effects.add_child(scent)
  scent_trail.push_front(scent)

Jika Anda ingin bau terlihat selama debugging, Anda dapat menambahkan node ColorRect ke mereka, dan kemudian sembunyikan saja. Setelah melakukan ini, Anda akan melihat bahwa ketika mengejar pemain ada jejak bau.

Sekarang kita perlu membangkitkan musuh-musuh anjing pelacak internal sehingga mereka mengikuti aroma baru ini ketika mereka tidak melihat pemain. Tetapi untuk ini kita perlu menambahkan node RayCast2D ke musuh, dan mengatur Layers Fisika di Godot sehingga balok tahu apa yang bisa dilakukan dengan tabrakan.

Lapisan Fisika


Untuk mengatur Layers Fisika di Godot, Anda perlu mengklik Project di menu atas dan kemudian pada Pengaturan Proyek, kemudian pergi ke bagian Layer Names di sudut kiri bawah dan kemudian pilih Fisika 2D.


Beri mereka nama yang cocok. Setelah itu, buka objek dalam game dan rentangkan Collision di sidebar Property Inspector, lalu klik ยทยท untuk menetapkannya. Untuk objek, mereka harus ditetapkan sebagai Layers.


Setelah menetapkan Layers Fisika ke objek, Anda perlu mengubah RayCast2D dari musuh sehingga memeriksa lapisan-lapisan yang tidak dapat dilewati oleh musuh (dalam kasus kami, ini solid, objek, peti, lubang, gate_closed).

Setelah mengatur Layers Fisika, langkah terakhir adalah mengubah status Chase.

# ChaseState.gd

func _init(enemy, params):
  chase_target()

func chase_target():
  var look     = enemy.get_node("RayCast2D")
  look.cast_to = (enemy.target.position - enemy.position)
  look.force_raycast_update()

  # if we can see the target, chase it
  if !look.is_colliding():
    enemy.dir = look.cast_to.normalized()

  # or chase first scent we can see
  else:
    for scent in enemy.target.scent_trail:
      look.cast_to = (scent.position - enemy.position)
      look.force_raycast_update()

      if !look.is_colliding():
        enemy.dir = look.cast_to.normalized()
        break

func _physics_process(delta):
  var motion = enemy.dir * enemy.speed
  enemy.move_and_slide(motion)

Sekarang, ketika musuh memasuki negara Chase, dia mulai mencoba untuk melemparkan kembali pemain, dan jika tidak ada yang menghalangi, dia akan mengikutinya! Jika ada sesuatu di jalan, maka dia pergi ke jejak bau dan mencoba untuk membuang masing-masing sampai dia menemukan salah satu dari mereka, dan kemudian - mengejarnya!


Dan sekarang semuanya berfungsi, musuh berubah menjadi anjing pelacak. Untuk meningkatkan sistem, dimungkinkan untuk menerapkan sistem menghindari tabrakan antara musuh, tetapi ini adalah topik untuk artikel terpisah.

All Articles