Game menara pertahanan semakin populer, dan ini tidak mengherankan - sedikit yang bisa dibandingkan dengan kesenangan mengamati garis pertahanan Anda sendiri yang menghancurkan musuh-musuh jahat! Dalam tutorial dua bagian ini, kita akan membuat game menara pertahanan di mesin 
Unity !
Anda akan belajar bagaimana melakukan hal berikut:
- Buat gelombang musuh
- Buat mereka mengikuti titik rute
- Bangun dan tingkatkan menara, dan juga ajarkan mereka cara memecah musuh menjadi piksel kecil
Pada akhirnya, kita mendapatkan kerangka permainan, yang dapat dikembangkan lebih lanjut!
Catatan : Anda memerlukan pengetahuan Unity dasar (misalnya, Anda perlu tahu bagaimana aset dan komponen ditambahkan, apa cetakan) dan dasar-dasar C # . Untuk mempelajari semua ini, saya sarankan Anda membaca tutorial tentang Unity oleh Sean Duffy atau seri Beginning C # with Unity oleh Brian Mockley.
Saya akan bekerja di Unity untuk OS X, tetapi tutorial ini juga cocok untuk Windows.
Melalui jendela menara gading
Dalam tutorial ini, kami akan membuat game menara pertahanan tempat musuh (bug kecil) merangkak ke cookie milik Anda dan antek Anda (tentu saja, ini adalah monster!). Pemain dapat menempatkan monster di titik-titik strategis dan meningkatkannya untuk emas.
Pemain harus membunuh semua bug sampai mereka mendapatkan cookie. Setiap gelombang musuh baru menjadi semakin sulit dikalahkan. Permainan berakhir ketika Anda selamat dari semua gelombang (kemenangan!) Atau ketika lima musuh merangkak ke cookie (kalah!).
Ini adalah screenshot dari game yang sudah selesai:
Monster, satukan! Lindungi cookie!Mulai bekerja
Unduh 
proyek ini 
kosong , buka 
zipnya , dan buka proyek 
TowerDefense-Part1-Starter di Unity.
Proyek draft memiliki aset grafik dan suara, animasi siap pakai dan beberapa skrip yang berguna. Skrip tidak terkait langsung dengan game menara pertahanan, jadi saya tidak akan membicarakannya di sini. Namun, jika Anda ingin mempelajari lebih lanjut tentang membuat animasi 2D di Unity, lihat 
tutorial Unity 2D ini .
Proyek ini juga mengandung cetakan, yang akan kami tambahkan nanti untuk membuat karakter. Akhirnya, ada adegan dalam proyek dengan latar belakang dan antarmuka pengguna yang disesuaikan.
Buka 
GameScene yang terletak di folder 
Adegan dan atur mode Game ke rasio aspek 
4: 3 sehingga semua label cocok dengan latar belakang dengan benar. Dalam mode Game, Anda akan melihat yang berikut:
Karangan:- Grafik untuk proyek ini diambil dari paket Wiki Wenderlich gratis! Karya grafis lainnya dapat ditemukan di situs web gameartguppy- nya.
- Musik yang hebat diambil dari BenSound , yang memiliki soundtrack keren lainnya!
- Saya juga berterima kasih kepada Michael Jesper untuk fungsi goyangan kamera yang sangat berguna .
.
Tempat itu ditandai dengan tanda silang: lokasi monster
Monster hanya bisa ditempatkan pada titik yang ditandai dengan 
x .
Untuk menambahkannya ke adegan, seret 
Images \ Objects \ openspot dari 
Project Browser ke jendela 
Scene . Sementara posisi itu tidak penting bagi kami.
Setelah Anda memilih 
Openspot dalam hierarki, klik 
Tambahkan Komponen di 
Inspektur dan pilih 
Box Collider 2D . Di jendela Scene, Unity akan menampilkan collider persegi panjang dengan garis hijau. Kami akan menggunakan collider ini untuk mengenali klik mouse di lokasi ini.
Tambahkan komponen 
Audio \ Audio Source ke 
Openspot dengan cara yang sama. Untuk parameter 
AudioClip komponen Sumber Audio, pilih file 
tower_place yang terletak di folder 
Audio dan nonaktifkan 
Play On Sedarlah .
Kita perlu membuat 11 poin lagi. Meskipun ada godaan untuk mengulangi semua langkah ini, Unity memiliki solusi yang lebih baik: 
Prefab !
Seret 
Openspot dari 
Hierarki ke folder 
Rak itan di dalam 
Browser Proyek . Namanya akan berubah menjadi biru dalam Hierarki, yang artinya melekat pada cetakan. Sesuatu seperti ini:
Sekarang kami memiliki cetakan prefab, kami dapat membuat salinan sebanyak yang kami suka. Cukup seret dan lepas 
Openspot dari folder 
Rak itan di dalam 
Browser Proyek ke dalam jendela 
Adegan . Ulangi ini 11 kali dan 12 objek openspot akan muncul di layar.
Sekarang gunakan 
Inspektur untuk mengatur 12 objek OpenSpot ini dengan koordinat berikut:
- (X: -5.2, Y: 3.5, Z: 0)
- (X: -2.2, Y: 3.5, Z: 0)
- (X: 0,8, Y: 3,5, Z: 0)
- (X: 3,8, Y: 3,5, Z: 0)
- (X: -3,8, Y: 0,4, Z: 0)
- (X: -0,8, Y: 0,4, Z: 0)
- (X: 2.2, Y: 0.4, Z: 0)
- (X: 5.2, Y: 0.4, Z: 0)
- (X: -5.2, Y: -3.0, Z: 0)
- (X: -2.2, Y: -3.0, Z: 0)
- (X: 0,8, Y: -3,0, Z: 0)
- (X: 3,8, Y: -3,0, Z: 0)
Ketika Anda melakukan ini, pemandangannya akan terlihat seperti ini:
Kami menempatkan monster
Untuk mempermudah penempatan, ada 
Rakasa Rak 
Rak di folder 
Rak Gudang proyek.
Monster Rakasa Siap PakaiSaat ini, itu terdiri dari objek permainan kosong dengan tiga sprite yang berbeda dan animasi penembakan sebagai anak-anak.
Setiap sprite adalah monster dengan tingkat kekuatan yang berbeda. Rak pabrikan juga berisi komponen 
Sumber Audio , yang akan diluncurkan untuk memutar suara ketika monster menembakkan laser.
Sekarang kita akan membuat skrip yang akan 
meng - 
host Monster di 
Openspot .
Di 
Browser Proyek, pilih objek 
Openspot di folder 
Rak itan . Di 
Inspektur, klik 
Tambah Komponen , lalu pilih 
Script Baru dan 
beri nama script 
PlaceMonster . Pilih 
C Sharp sebagai bahasa dan klik 
Buat dan Tambah . Karena kami menambahkan skrip ke prefab 
Openspot , semua objek Openpot dalam adegan sekarang akan memiliki skrip ini. Hebat!
Klik dua kali pada skrip untuk membukanya di IDE. Kemudian tambahkan dua variabel:
public GameObject monsterPrefab; private GameObject monster; 
Kami akan membuat instance objek yang disimpan di 
monsterPrefab untuk membuat monster, dan menyimpannya di 
monster sehingga dapat dimanipulasi selama permainan.
Satu monster per poin
Agar hanya satu monster yang dapat diletakkan pada satu titik, tambahkan metode berikut:
 private bool CanPlaceMonster() { return monster == null; } 
Di 
CanPlaceMonster() kita dapat memeriksa apakah variabel 
monster masih 
null . Jika demikian, maka tidak ada monster di titik itu, dan kita bisa menempatkannya.
Sekarang tambahkan kode berikut untuk menempatkan monster ketika pemain mengklik GameObject ini:
 
Kode ini menemukan monster ketika Anda mengklik mouse atau menyentuh layar. Bagaimana cara kerjanya?
- Unity secara otomatis memanggil OnMouseUpketika seorang pemain menyentuh GameObject fisik collider.
- Ketika dipanggil, metode ini menempatkan monster jika CanPlaceMonster()mengembalikantrue.
- Kami membuat monster menggunakan metode Instantiate, yang membuat instance dari prefab yang diberikan dengan posisi dan rotasi yang ditentukan. Dalam hal ini, kami menyalinmonsterPrefab, memberikannya posisi GameObject saat ini dan tidak ada rotasi, mentransfer hasilnya keGameObjectdan menyimpannya kemonster
- Pada akhirnya, kami memanggil PlayOneShotuntuk memainkan efek suara yang melekat pada komponenAudioSourceobjek.
Sekarang skrip 
PlaceMonster kami dapat memiliki monster baru, tetapi kami masih perlu menentukan cetakan.
Menggunakan Prefab Kanan
Simpan file dan kembali ke Unity.
Untuk mengatur variabel 
monsterPrefab , pertama-tama pilih objek 
Openspot dari folder 
Rak itan di browser proyek.
Di 
Inspektur, klik pada lingkaran di sebelah kanan bidang 
Rakasa Rakasa komponen 
PlaceMonster (Script) dan pilih 
Rakasa di kotak dialog yang muncul.
Itu saja. Luncurkan adegan dan buat monster di tempat yang berbeda dengan mengklik mouse atau menyentuh layar.
Hebat! Sekarang kita bisa membuat monster. Namun, mereka terlihat seperti kekacauan aneh, karena semua sprite anak monster itu ditarik. Sekarang kita akan memperbaikinya.
Naikkan level monster
Gambar di bawah ini menunjukkan bahwa dengan peningkatan level, monster terlihat semakin menakutkan.
Manis sekali! Tetapi jika Anda mencoba mencuri cookie-nya, monster ini akan berubah menjadi seorang pembunuh.Script digunakan sebagai dasar untuk implementasi sistem level monster. Ini melacak kekuatan monster di setiap level dan, tentu saja, level monster saat ini.
Tambahkan skrip ini.
Pilih 
Rak Pabrikan / Rakasa di 
Browser Proyek . Tambahkan skrip 
C # baru yang disebut 
MonsterData . Buka skrip di IDE dan tambahkan kode berikut di 
atas kelas 
MonsterData .
 [System.Serializable] public class MonsterLevel { public int cost; public GameObject visualization; } 
Jadi kami membuat 
MonsterLevel . Ini mengelompokkan harga (dalam emas, yang akan kami dukung di bawah) dan representasi visual dari tingkat monster.
Kami menambahkan di atas 
[System.Serializable] sehingga instance kelas dapat dimodifikasi di inspektur. Ini memungkinkan kita untuk dengan cepat mengubah semua nilai kelas Level, bahkan ketika game sedang berjalan. Ini sangat berguna untuk menyeimbangkan permainan.
Mengatur Level Monster
Dalam kasus kami, kami akan menyimpan 
MonsterLevel ditentukan di 
List<T> .
Mengapa tidak menggunakan 
MonsterLevel[] ? Kita perlu indeks objek 
MonsterLevel tertentu beberapa kali. Meskipun mudah untuk menulis kode untuk ini, kita masih harus menggunakan 
IndexOf() , yang mengimplementasikan fungsionalitas 
Lists . Tidak masuk akal untuk menemukan kembali roda.
Menciptakan kembali sepeda motor biasanya merupakan ide yang buruk.Di bagian atas 
MonsterData.cs, tambahkan konstruksi berikut 
using :
 using System.Collections.Generic; 
Ini memberi kita akses ke struktur data umum sehingga kita bisa menggunakan kelas 
List<T> dalam skrip.
Catatan : generalisasi adalah konsep C # yang kuat. Mereka memungkinkan Anda untuk menentukan struktur data tipe aman tanpa harus mematuhi tipe tersebut. Ini berguna untuk kelas kontainer seperti daftar dan set. Untuk mempelajari lebih lanjut tentang struktur generik, baca buku Pengantar C # Generik .
Sekarang tambahkan variabel berikut ke 
MonsterData untuk menahan daftar 
MonsterLevel :
 public List<MonsterLevel> levels; 
Berkat generalisasi, kami dapat menjamin bahwa 
List dari 
level hanya akan berisi objek 
MonsterLevel .
Simpan file dan beralih ke Unity untuk mengkonfigurasi setiap level.
Pilih 
Rak itan / Rakasa di 
Browser Proyek . 
Inspektur sekarang menampilkan bidang 
Levels dari komponen 
MonsterData (Script) . Atur 
ukuran ke 
3 .
Selanjutnya, tetapkan 
biaya untuk setiap level:
- Elemen 0 : 200
- Elemen 1 : 110
- Elemen 2 : 120
Sekarang kami menetapkan nilai bidang tampilan visual.
Perluas 
Rakasa / Rakasa di peramban Proyek untuk melihat anak-anaknya. Tarik anak 
Monster0 ke dalam bidang 
Elemen 0 visualisasi .
Selanjutnya, atur 
Elemen 1 ke 
Monster1 , dan 
Elemen 2 ke 
Monster2 . GIF menunjukkan proses ini:
Saat Anda memilih 
Rak itan / Rakasa , 
Rak itan akan terlihat seperti ini:
Setel level saat ini
Kembali ke 
MonsterData.cs di IDE dan tambahkan variabel lain ke 
MonsterData .
 private MonsterLevel currentLevel; 
Dalam variabel private 
currentLevel kita akan menyimpan level monster saat ini.
Sekarang atur 
currentLevel dan buat itu terlihat oleh skrip lain. Tambahkan baris berikut ke 
MonsterData bersama dengan deklarasi variabel instan:
 
Potongan kode C # yang cukup besar, bukan? Mari kita lakukan secara berurutan:
- Atur properti variabel currentLevelvariabel. Dengan mengatur properti, kita dapat menyebutnya seperti variabel lain: baik sebagaiCurrentLevel(di dalam kelas) atau sebagaimonster.CurrentLevel(di luar). Kita dapat mendefinisikan perilaku apa pun dalam metode pengambil atau penyetel properti, dan dengan hanya membuat pengambil, penyetel, atau keduanya, kita dapat mengontrol properti properti: baca-saja, hanya-tulis, dan tulis / baca.
- Di pengambil, kami mengembalikan nilai currentLevel.
- Di setter, kami menetapkan currentLevelnilai baru. Kemudian kita mendapatkan indeks level saat ini. Akhirnya, kami menggilir semua tingkatan dan mengaktifkan / menonaktifkan tampilan visual tergantung padacurrentLevelIndex. Ini bagus karena ketikacurrentLevelberubah, sprite memperbarui secara otomatis. Properti adalah hal yang sangat nyaman!
Tambahkan implementasi 
OnEnable berikut:
 void OnEnable() { CurrentLevel = levels[0]; } 
Di sini kita mengatur 
CurrentLevel saat menempatkan. Ini memastikan bahwa hanya sprite yang diinginkan yang ditampilkan.
Catatan : penting untuk menginisialisasi properti di OnEnable , dan bukan di OnStart , karena kami memanggil metode ordinal saat membuat instance prefab.
OnEnable akan dipanggil segera ketika cetakan dibuat (jika cetakan disimpan dalam keadaan diaktifkan), tetapi OnStart tidak dipanggil sampai objek mulai berjalan sebagai bagian dari adegan.
Kami perlu memverifikasi data ini sebelum menempatkan monster, jadi kami inisialisasi ke OnEnable .
Simpan file dan kembali ke Unity. Jalankan proyek dan tempatkan monster; mereka sekarang menampilkan sprite yang benar dari level terendah.
Peningkatan Monster
Kembali ke IDE dan tambahkan metode berikut ke 
MonsterData :
 public MonsterLevel GetNextLevel() { int currentLevelIndex = levels.IndexOf (currentLevel); int maxLevelIndex = levels.Count - 1; if (currentLevelIndex < maxLevelIndex) { return levels[currentLevelIndex+1]; } else { return null; } } 
Di 
GetNextLevel kita mendapatkan indeks 
currentLevel dan indeks level tertinggi; jika monster belum mencapai level maksimum, maka level berikutnya kembali. Jika tidak, 
null dikembalikan.
Anda dapat menggunakan metode ini untuk mengetahui apakah upgrade monster dimungkinkan.
Untuk menaikkan level monster, tambahkan metode berikut:
 public void IncreaseLevel() { int currentLevelIndex = levels.IndexOf(currentLevel); if (currentLevelIndex < levels.Count - 1) { CurrentLevel = levels[currentLevelIndex + 1]; } } 
Di sini kita mendapatkan indeks level saat ini, dan kemudian memastikan bahwa ini bukan level maksimum, memeriksa bahwa itu kurang dari level. 
levels.Count - 1 . Jika demikian, maka 
CurrentLevel ke level berikutnya.
Memeriksa Fungsi Peningkatan
Simpan file dan kembali ke 
PlaceMonster.cs di IDE. Tambahkan metode baru:
 private bool CanUpgradeMonster() { if (monster != null) { MonsterData monsterData = monster.GetComponent<MonsterData>(); MonsterLevel nextLevel = monsterData.GetNextLevel(); if (nextLevel != null) { return true; } } return false; } 
Pertama kita periksa apakah ada monster yang bisa diperbaiki dengan membandingkan variabel 
monster dengan 
null . Jika ini benar, maka kita mendapatkan level monster saat ini dari 
MonsterData -nya.
Kemudian kami memeriksa apakah level berikutnya tersedia, yaitu, apakah 
GetNextLevel() tidak mengembalikan 
null . Jika peningkatan level dimungkinkan, maka kami mengembalikan 
true ; jika tidak, kembalikan 
false .
Kami menerapkan peningkatan untuk emas
Untuk mengaktifkan opsi pemutakhiran, tambahkan cabang 
else if ke 
OnMouseUp :
 if (CanPlaceMonster()) {  
Kami memeriksa kemungkinan peningkatan menggunakan 
CanUpgradeMonster() . Jika memungkinkan, kita mengakses komponen 
GetComponent() menggunakan 
GetComponent() dan memanggil 
IncreaseLevel() , yang meningkatkan level monster. Akhirnya, kami meluncurkan Monster 
AudioSource .
Simpan file dan kembali ke Unity. Jalankan game, tempatkan dan tingkatkan 
sejumlah monster (tetapi untuk sekarang).
Membayar Emas - Manajer Game
Meskipun kita bisa segera membangun dan meningkatkan monster apa pun, tetapi apakah itu akan menarik dalam game?
Mari kita lihat masalah emas. Masalah dengan pelacakan itu adalah kita harus mentransfer informasi antara objek permainan yang berbeda.
Gambar di bawah ini menunjukkan semua objek yang harus mengambil bagian dalam hal ini.
Semua objek permainan yang dipilih harus tahu berapa banyak emas yang dimiliki pemain.Untuk menyimpan data ini, kami akan menggunakan objek umum yang dapat diakses oleh objek lain.
Klik kanan pada 
Hierarki dan pilih 
Buat Kosong . Beri nama objek 
GameManager baru.
Tambahkan skrip 
C # baru yang disebut 
GameManagerBehavior ke GameManager , lalu buka di IDE. Kami akan menampilkan jumlah total emas pemain di label, jadi di bagian atas file tambahkan baris berikut:
 using UnityEngine.UI; 
Ini akan memungkinkan kita untuk mengakses kelas UI seperti 
Text , yang digunakan untuk label. Sekarang tambahkan variabel berikut ke kelas:
 public Text goldLabel; 
Ini akan menyimpan tautan ke komponen 
Text digunakan untuk menampilkan jumlah emas yang dimiliki pemain.
Sekarang 
GameManager tahu tentang label, bagaimana kita menyinkronkan jumlah emas yang disimpan dalam variabel dan nilai yang ditampilkan dalam label? Kami akan membuat properti.
Tambahkan kode berikut ke 
GameManagerBehavior :
 private int gold; public int Gold { get { return gold; } set { gold = value; goldLabel.GetComponent<Text>().text = "GOLD: " + gold; } } 
Apakah dia tampak akrab? Kode ini mirip dengan 
CurrentLevel , yang kami atur di 
Monster . Pertama kita membuat variabel 
gold pribadi untuk menampung jumlah emas saat ini. Lalu kita atur properti 
Gold (tiba-tiba, kan?) Dan terapkan pengambil dan penyetel.
Sang pengambil hanya mengembalikan nilai 
gold . Setter lebih menarik. Selain mengatur nilai variabel, itu juga menetapkan bidang 
text untuk 
goldLabel untuk menampilkan nilai emas baru.
Bagaimana kita akan bermurah hati? Tambahkan baris berikut ke 
Start() untuk memberi pemain 
1000 emas, atau kurang jika Anda menyesal atas uang itu:
 Gold = 1000; 
Menetapkan objek label ke skrip
Simpan file dan kembali ke Unity. Di 
Hirarki, pilih 
GameManager . Di 
Inspektur, klik pada lingkaran di sebelah kanan 
Label Emas . Di kotak dialog 
Select Text , pilih tab 
Scene dan pilih 
GoldLabel .
Jalankan adegan dan label akan menampilkan 
Emas: 1000 .
Memeriksa "dompet" pemain
Buka skrip 
PlaceMonster.cs di IDE dan tambahkan variabel instance berikut:
 private GameManagerBehavior gameManager; 
Kami akan menggunakan 
gameManager untuk mengakses komponen 
GameManagerBehavior dari objek 
GameManagerBehavior di layar. Untuk menentukannya, tambahkan yang berikut ke 
Start() :
 gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>(); 
Kami mendapatkan GameObject bernama GameManager menggunakan fungsi 
GameObject.Find() , yang mengembalikan objek game pertama yang ditemukan dengan nama itu. Kemudian kita mendapatkan komponen 
GameManagerBehavior dan menyimpannya untuk masa depan.
Catatan : Anda bisa melakukan ini dengan menyetel bidang di editor Unity atau dengan menambahkan metode statis ke GameManager yang mengembalikan instance singleton dari mana kita bisa mendapatkan GameManagerBehavior .
Namun, dalam blok kode yang ditunjukkan di atas ada kuda hitam: metode Find , yang bekerja lebih lambat selama eksekusi aplikasi; tetapi nyaman dan dapat digunakan dalam jumlah sedang.
Ambil uangku!
Kami belum mengurangi emas, jadi kami akan menambahkan baris ini 
dua kali ke 
OnMouseUp() , menggantikan masing-masing komentar 
// TODO: :
 gameManager.Gold -= monster.GetComponent<MonsterData>().CurrentLevel.cost; 
Simpan file dan kembali ke Unity, perbarui beberapa monster dan lihat pembaruan nilai Gold. Sekarang kami mengurangi emas, tetapi pemain dapat membangun monster selama mereka memiliki cukup ruang; mereka hanya meminjam uang.
Kredit tak terbatas? Hebat! Tapi kita tidak bisa membiarkannya. Pemain harus bisa bertaruh monster sementara dia memiliki cukup emas.Cek Emas untuk Monster
Beralih di IDE ke 
PlaceMonster.cs dan ganti konten 
CanPlaceMonster() berikut:
 int cost = monsterPrefab.GetComponent<MonsterData>().levels[0].cost; return monster == null && gameManager.Gold >= cost; 
Kami 
MonsterData penempatan monster dari 
levels di 
MonsterData -nya. Lalu kita periksa 
monster bukan 
null , dan itu 
gameManager.Gold lebih dari harga ini.
Tugas untuk Anda: tambahkan secara independen ke 
CanUpgradeMonster() centang apakah pemain memiliki cukup emas.
Solusi di dalamGanti baris:
 return true; 
tentang ini:
 return gameManager.Gold >= nextLevel.cost; 
Ini akan memeriksa apakah pemain memiliki lebih banyak 
Emas daripada harga upgrade.
 Simpan dan jalankan adegan di Unity. Sekarang cobalah cara menambahkan monster tanpa batas!
Sekarang kita hanya dapat membangun sejumlah monster.Kebijakan menara: musuh, gelombang, dan titik arah
Inilah saatnya untuk "membuka jalan" bagi musuh-musuh kita. Musuh muncul di titik pertama rute, pindah ke yang berikutnya dan ulangi prosesnya hingga mencapai cookie.
Anda dapat membuat musuh bergerak seperti ini:
- Atur jalan yang akan diikuti musuh
- Pindahkan musuh di sepanjang jalan
- Putar musuh sehingga dia melihat ke depan
Membuat jalan dari titik arah
Klik kanan pada 
Hierarchy dan pilih 
Create Empty untuk membuat objek game baru yang kosong. Beri nama 
Jalan dan posisikan di 
(0, 0, 0) .
Sekarang klik kanan pada 
Road in the 
Hierarchy dan buat objek game kosong lainnya sebagai anak Road. Beri nama 
Waypoint0 dan letakkan di titik 
(-12, 2, 0) - dari sini musuh akan memulai gerakan mereka.
Demikian pula, buat lima titik rute lagi dengan nama dan posisi berikut:
- Waypoint1: (X: 7, Y: 2, Z: 0)
- Waypoint2: (X: 7, Y: -1, Z: 0)
- Waypoint3: (X: -7.3, Y: -1, Z: 0)
- Waypoint4: (X: -7.3, Y: -4.5, Z: 0)
- Waypoint5: (X: 7, Y: -4.5, Z: 0)
Tangkapan layar di bawah ini menunjukkan titik rute dan jalur yang dihasilkan.
Membuat musuh
Sekarang buat beberapa musuh sehingga mereka bisa bergerak di sepanjang jalan. Ada prefab 
Musuh di folder 
Rak itan . Posisinya adalah 
(-20, 0, 0) , jadi instance baru akan dibuat di luar layar.
Dalam semua hal lain, ini dikonfigurasi hampir dengan cara yang sama seperti Rakasa Rakasa, memiliki 
AudioSource dan anak 
Sprite , dan kita dapat memutar sprite ini di masa depan tanpa memutar bar kesehatan.
Kami menggerakkan musuh di sepanjang jalan
Tambahkan skrip 
C # baru yang disebut 
MoveEnemy ke 
prefab \ prefab Musuh . Buka skrip di IDE dan tambahkan variabel berikut:
 [HideInInspector] public GameObject[] waypoints; private int currentWaypoint = 0; private float lastWaypointSwitchTime; public float speed = 1.0f; 
Di 
waypoints , salinan titik rute disimpan dalam array, dan baris 
[HideIn inspector ] atas 
waypoints memastikan bahwa kami tidak dapat secara tidak sengaja mengubah bidang ini di 
Inspektur , tetapi masih akan memiliki akses ke sana dari skrip lain.
currentWaypoint melacak dari mana rute musuh dari pada saat ini, dan 
lastWaypointSwitchTime menyimpan waktu ketika musuh melewatinya. Selain itu, kami menyimpan 
speed musuh.
Tambahkan baris ini ke 
Start() :
 lastWaypointSwitchTime = Time.time; 
Jadi kami menginisialisasi 
lastWaypointSwitchTime dengan nilai waktu saat ini.
Agar musuh bergerak di sepanjang rute, tambahkan kode berikut ke 
Update() :
 
Mari kita menganalisis kode langkah demi langkah:
- Dari berbagai titik rute, kami mendapatkan posisi awal dan akhir dari segmen rute saat ini.
- Kami menghitung waktu yang diperlukan untuk mencakup seluruh jarak menggunakan rumus waktu = jarak / kecepatan , dan kemudian menentukan waktu saat ini pada rute. Menggunakan Vector2.Lerp, kami menginterpolasi posisi musuh saat ini antara segmen awal dan akhir yang tepat.
- Periksa apakah musuh telah mencapai endPosition. Jika ya, maka kami memproses dua skenario yang mungkin:
 - Musuh belum mencapai titik terakhir rute, jadi tambah nilai currentWaypointdan perbaruilastWaypointSwitchTime. Nanti kita akan menambahkan kode untuk mengubah musuh sehingga dia melihat ke arah gerakannya.
- Musuh telah mencapai titik terakhir dari rute, lalu kita hancurkan dan mulai efek suara. Nanti kita akan menambahkan kode yang mengurangi healthpemain.
 
Simpan file dan kembali ke Unity.
Kami memberi tahu musuh tentang arah gerakan
Dalam kondisi saat ini, musuh tidak mengetahui urutan titik rute.
Pilih 
Jalan di 
Hirarki dan tambahkan skrip 
C # baru yang disebut 
SpawnEnemy . Buka di IDE dan tambahkan variabel berikut:
 public GameObject[] waypoints; 
Kami akan menggunakan 
waypoints untuk menyimpan referensi ke titik lewat dalam adegan dalam urutan yang diinginkan.
Simpan file dan kembali ke Unity. Pilih 
Road di 
Hierarchy dan atur 
Size of the 
Waypoints array menjadi 
6 .
Seret setiap anak Jalan ke dalam bidang dengan menempelkan 
Waypoint0 di 
Elemen 0 , 
Waypoint1 di 
Elemen 1, dan seterusnya.
Sekarang kami memiliki array yang berisi titik rute dalam urutan yang benar - ingat, musuh tidak pernah mundur, mereka terus-menerus berjuang untuk mendapatkan hadiah yang manis.
Periksa cara kerjanya
Buka 
SpawnEnemy di IDE dan tambahkan variabel berikut:
 public GameObject testEnemyPrefab; 
Ini akan menyimpan referensi ke 
testEnemyPrefab Musuh di 
testEnemyPrefab .
Untuk membuat musuh saat menjalankan skrip, tambahkan kode berikut ke 
Start() :
 Instantiate(testEnemyPrefab).GetComponent<MoveEnemy>().waypoints = waypoints; 
Jadi kami akan membuat salinan cetakan baru yang disimpan di 
testEnemy dan memberinya rute.
Simpan file dan kembali ke Unity. Pilih objek 
Jalan di 
Hirarki dan pilih prefab 
Musuh untuk parameter 
Uji Musuh .
Luncurkan proyek dan lihat bagaimana musuh bergerak di sepanjang jalan (di GIF, untuk kejelasan, kecepatannya meningkat 20 kali).Melihat bahwa dia tidak selalu melihat ke mana dia pergi? Ini lucu, tapi kami mencoba membuat game profesional. Oleh karena itu, di bagian kedua tutorial kami akan mengajarkan musuh untuk berharap.Ke mana harus pergi selanjutnya?
Kami telah melakukan banyak hal dan dengan cepat bergerak menuju pembuatan game pertahanan menara kami sendiri.Pemain dapat membuat sejumlah monster, dan musuh berlari di sepanjang jalan, menuju cookie kami. Pemain memiliki emas dan mereka dapat meningkatkan monster.Unduh hasil akhirnya dari sini .Pada bagian kedua, kita akan mempertimbangkan penciptaan gelombang besar musuh dan kehancuran mereka. Sampai ketemu lagi!