Bagaimana kode Monster Loot Drops
() translation by (you can also view the original English article)
Sebuah mekanik yang umum dalam game action adalah adanya musuh yang dapat mengurangi beberapa jenis item atau hadiah saat hampir mati. Karakter itu dapat mengumpulkan hasil curian/loot untuk mendapatkan beberapa keuntungan. Mekanik ini banyak diharapkan dalam pertandingan, seperti RPG, karena memberikan dorongan pemain untuk menyingkirkan musuh-serta melakukan ledakan kecil dari endorfin ketika menemukan hadiah.
Dalam tutorial ini, kami akan meninjau inner mekanik tersebut dan melihat bagaimana cara untuk menerapkannya, dengan apa pun jenis permainan serta alat coding / bahasa yang Anda gunakan.
Pada contoh kali ini saya gunakan demonstrate yang dibuat menggunakan Membangun 2, sebuah alat membuat permainan HTML5, tapi tidak secara khusus dengan alat itu. Anda harus dapat menerapkan mekanik yang sama pada bahasa coding atau alat yang digunakan.
Contoh dibuat di r167.2 dan dapat dibuka serta diedit dalam software
versi gratis. Anda dapat men-download versi terbaru dari Construct 2 disini (sejak saya mulai
menulis artikel ini, setidaknya ada dua versi yang lebih baru telah dirilis)
dan dengan contoh yang sesuai keinginan Anda. Sumber file contoh CAPX yang
melekat pada tutorial ini dalam file bentuk zip. Sumber file contoh CAPX yang melekat pada tutorial ini dalam file bentuk zip.
The Mechanic Basic



Fungsi dipanggil Setelah kematian musuh (ketika HP kurang dari atau sama dengan nol). Peran fungsi ini adalah untuk menentukan apakah ada penurunan atau tidak, dan, jika ada pengurangan maka jenis harus dijatuhkan.
Fungsi ini juga dapat menangani penciptaan representasi visual dari drop, pemijahan di bekas koordinat layar musuh.
Perhatikan contoh berikut:
Klik tombol Bunuhlah 100 Beasts. Kemudian akan menjalankan proses batch yang menciptakan 100 binatang acak, bunuh mereka, dan akan menampilkan hasilnya untuk setiap binatang (yaitu, apakah binatang itu menghancurkan item, dan jika iya jenis barang apa). Di bagian bawah tampilan layar terdapat statistic yang menyatakan berapa banyak binatang yang menjatuhkan item, dan berapa banyak setiap jenis item yang dijatuhkan.
Contoh ini adalah berisi teks yang dapat menunjukkan logika di balik fungsi, dan mekanik ini dapat diterapkan untuk semua jenis permainan, baik platformer yang mana Anda menginjak musuh, atau top-down tampilan shooter, atau RPG.
Mari kita lihat
bagaimana demo ini bekerja. Pertama, binatang dan drop masing-masing terkandung dalam aturan. Berikut aturan binatang
:
Index
(X) | Name
(Y-0) | Drop
rate (Y-1) | Kelangkaan
item (Y-2) |
0 | Boar | 100 | 100 |
1 | Goblin | 75 | 75 |
2 | Squire | 65 | 55 |
3 | ZogZog | 45 | 100 |
4 | Owl | 15 | 15 |
5 | Mastodon | 35 | 50 |
Dan inilah aturan drops
:
Index (X) | Name (Y-0) | Kelangkaan
item (Y-1) |
0 | Lollipop | 75 |
1 | Gold | 50 |
2 | Rocks | 95 |
3 | Jewel | 25 |
4 | Incense | 35 |
5 | Equipment | 15 |
nilai X
(Index
kolom) menyatakan aturan yang digunakan sebagai
identifikasi keunikan untuk binatang atau jenis item. Misalnya, binatang indeks 0
adalah Boar
. Item indeks 3
adalah Jewel
.
Aturan ini bertindak sebagai tabel lookup bagi kita, berisi nama atau jenis setiap binatang atau item, serta nilai-nilai lain yang memungkinkan kita untuk menentukan kelangkaan atau tingkat drop. Dalam aturan binatang, ada dua kolom lagi setelah nama:
Drop rate adalah
seberapa besar kemungkinan binatang itu menjatuhkan item saat dibunuh. Misalnya, babi akan memiliki 100% kesempatan untuk menjatuhkan item saat dibunuh, sedangkan burung hantu memiliki 15% kesempatan untuk melakukan hal yang sama.
Kelangkaan
mendefinisikan item yang jarang dijatuhkan oleh binatang ini. Misalnya, babi hutan akan cenderung drop item dengan nilai kelangkaan 100. Sekarang, jika kita memeriksa aturan drop, kita dapat melihat bahwa batu-batu adalah item dengan kelangkaan terbesar (95). (Meskipun tingginya nilai kelangkaan disebabkan karena cara saya program pada fungsi, dengan semakin besar jumlah kelangkaan menyatakan semakin umumnya item tersebut. Batu akan memiliki kesempatan lebih besaruntuk dijatuhkan dibandingkan item dengan nilai kelangkaan rendah.)
Dan yang menarik bagi kita mengenai perspektif desain game. Untuk keseimbangan permainan, kami tidak ingin pemain mendapatkan akses terlalu banyak peralatan atau terlalu banyak item high-end -jika tidak seperti itu, karakter mungkin akan mudah menguasai, dan permainan akan kurang menarik untuk dimainkan .
Tabel dan nilai-nilai tersebut hanya merupakan contoh, dan Anda dapat bermain dengan menyesuaikannya sistem permainan Anda sendiri dan permainan pada umumnya. Itu semua tergantung pada keseimbangan sistem Anda. Jika Anda ingin mempelajari lebih lanjut masalah balancing, saya sarankan Anda mempelajari rangkaian tutorial: Balancing Turn-Based RPGs.
Sekarang mari kita lihat pseudo kode untuk demo:
1 |
CONSTANT BEAST_NAME = 0 |
2 |
CONSTANT BEAST_DROPRATE = 1 |
3 |
CONSTANT BEAST_RARITY = 2 |
4 |
CONSTANT DROP_NAME = 0 |
5 |
CONSTANT DROP_RATE = 1 |
6 |
//Those constants are used for a better readability of the arrays |
7 |
|
8 |
On start of the project, fill the arrays with the correct values |
9 |
array aBeast(6,3) //The array that contains the values for each beast |
10 |
array aDrop(6,2) //The array that contains the values for each item |
11 |
array aTemp(0) //A temporary array that will allow us what item type to drop |
12 |
array aStats(6) //The array that will contain the amount of each item dropped |
13 |
|
14 |
On button clicked |
15 |
Call function "SlainBeast(100)" |
16 |
|
17 |
Function SlainBest (Repetitions) |
18 |
int BeastDrops = 0 //The variable that will keep the count of how many beasts did drop item |
19 |
Text.text = "" |
20 |
aStats().clear //Resets all the values contained in this array to make new statistics for the current batch |
21 |
Repeat Repetitions times |
22 |
int BeastType |
23 |
int DropChance |
24 |
int Rarity |
25 |
BeastType = Random(6) //Since we have 6 beasts in our array |
26 |
Rarity = aBeast(BeastType, BEAST_RARITY) //Get the rarity of items the beast should drop from the aBeast array |
27 |
DropChance = ceil(random(100)) //Picks a number between 0 and 100) |
28 |
Text.text = Text.text & loopindex & " _ " & aBeast(BeastType,BEAST_NAME) & "is slain" |
29 |
|
30 |
If DropChance > aBeast(BeastType,BEAST_DROPRATE) |
31 |
//The DropChance is bigger than the droprate for this beast |
32 |
Text.text = Text.text & "." & newline |
33 |
//We stop here, this beast is considered to not have dropped an item. |
34 |
|
35 |
If DropChance <= aBeast(BeastType,BEAST_DROPRATE) |
36 |
Text.text = Text.Text & " dropping " //We will put some text to display what item was dropped |
37 |
//On the other hand, DropChance is less or equal the droprate for this beast |
38 |
aTemp(0) //We clear/clean the aTemp array in which we will push entries to determine what item type to drop |
39 |
For a = 0 to aDrop.Width //We will loop through every elements of the aDrop array |
40 |
aDrop(a,DROP_RATE) >= Rarity //When the item drop rate is greater or equal the expected Rarity |
41 |
Push aTemp,a //We put the current a index in the temp array. We know that this index is a possible item type to drop |
42 |
int DropType |
43 |
DropType = random(aTemp.width) //The DropType is one of the indexes contained in the temporary array |
44 |
Text.text = Text.text & aDrop(DropType, DROP_NAME) & "." & newline //We display the item name that was dropped |
45 |
//We do some statistics |
46 |
aStats(DropType) = aStats(DropType) + 1 |
47 |
BeastDrops = BeastDrops + 1 |
48 |
TextStats.Text = BeastDrops & " beasts dropped items." & newline |
49 |
For a = 0 to aStats.width //Display each item amount that was dropped |
50 |
and aStats(a) > 0 |
51 |
TextStats.Text = TextStats.Text & aStats(a) & " " & aDrop(a,DROP_NAME) & " " |
52 |
tindakan Pertama,pengguna:
mengklik tombol Bunuhlah 100 Beasts. Tombol ini memanggil fungsi dengan parameter 100
, hanya karena 100 merupakan jumlah baik untuk membunuh musuh. Dalam permainan nyata, memungkinkan Anda untuk membunuh binatang satu per satu.
Dari ini, fungsi SlainBeast
dipanggil. Tujuannya adalah untuk menampilkan beberapa teks untuk memberikan feedback pada pengguna tentang apa yang terjadi. Pertama, membersihkan yang variabel BeastDrops dan aturan aStats , yang digunakan untuk statistik. Dalam permainan nyata, tidak mungkin Anda membutuhkan mereka. Ini dapat membersihkan Teks
juga, sehingga 100 baris akan ditampilkan untuk melihat hasil batch ini. Dalam fungsi itu sendiri, terdapat tiga variabel numerik yang diciptakan: BeastType
, DropChance
, dan Kelangkaan
.
BeastType
merupakan
indeks yang kita gunakan untuk merujuk baris tertentu dalam array aBeast
; yang pada
dasarnya merupakan jenis binatang yang yang harus dibunuh atau dihadapi pemain. Kelangkaan
diambil dari array aBeast
juga; itu kelangkaan item binatang ini harus dijatuhkan, nilai bidang kelangkaan Item
berada dalam array aBeast
.
Akhirnya, DropChance
adalah berisi nomor yang kami isikan secara acak antara 0
dan 100
. (Kebanyakan bahasa coding akan memiliki fungsi untuk mendapatkan nomor acak dalam jangkauan, atau setidaknya mendapatkan nomor acak antara 0
dan 1
, yang bisa Anda kalikan dengan 100
.)
pada titik ini, kita
dapat menampilkan bit pertama yang berisi informasi dalam objek Teks
: kita
sudah tahu jenis binatang apa yang melahirkan dan dibunuh. Jadi, kami menggabungkan nilai saat ini pada Text.text
BEAST_NAME
dalam BeastType
telah kami telah kami pilih secara acak, pada array aBeast
.
Berikutnya, kita harus menentukan item yang harus dijatuhkan. Kami melakukannya dengan membandingkan DropChancevalue
dengan nilai BEAST_DROPRATE
dari array aBeast
. Jika DropChance
kurang dari atau sama dengan nilai ini, kita drop item.
(Saya memutuskan untuk menggunakan pendekatan "kurang dari atau sama dengan", yang telah dipengaruhi oleh pemain peran hidup ini menggunakan D&D King Artur: Pendragon set of rules sebagai gulungan dadu, tetapi Anda bisa, memutuskan drop hanya akan terjadi ketika "lebih besar atau sama". ini hanya merupakan nilai-nilai numerik dan logika. Namun, jangan konsisten, dan tidak mengubah setengah logika selama alogaritma anda-jika tidak, Anda bisa mendapat masalah ketika mencoba debug atau mempertahankannya.)
Jadi, ada dua baris yang dapat menentukan apakah item dijatuhkan atau tidak. Pertama:
1 |
DropChance > aBeast(BeastType,BEAST_DROPRATE) |
Di sini, DropChance
lebih besar dari DropRate
, dan ini berarti ada item yang dijatuhkan. Dari sini, satu-satunya hal yang ditampilkan di penutupan adalah "" (titik) yang berakhir dengan kalimat, "[BeastType] dibunuh.", sebelum pindah ke musuh berikutnya dalam batch kami.
Di sisi lain:
1 |
DropChance <= aBeast(BeastType,BEAST_DROPRATE) |
Di sini, DropChance
kurang dari atau sama dengan DropRate
untuk BeastType
saat ini, dan hal ini
berarti item dijatuhkan. Untuk melakukannya, kita membandingkan antara Kelangkaan
item pada BeastType
saat ini "diperbolehkan" untuk menjatuhkan, dan beberapa nilai kelangkaan telah kami tetapkan dalam tabel aDrop
.
Kami loop melalui meja
aDrop
, memeriksa setiap indeks untuk melihat apakah DROP_RATE
lebih besar dari
atau sama dengan Kelangkaan
. (Ingat, kontra-intuitif, semakin tinggi nilai Kelangkaan
berarti bahwa item tersebut lebih umum) Untuk perbandingan yang cocok setiap indeks, kita memasukkan indeks ke dalam array sementara, aTemp
.
Pada akhir loop, kita
harus memiliki setidaknya satu indeks dalam array aTemp
. (Jika tidak, kita perlu mendesain ulang tabel aDrop
dan aBeast
!). Kita kemudian membuat variabel DropType
numerik baru secara acak dengan memilih salah satu indeks dari array aTemp
.; ini akan menjadi item drop kita.
Kami menambahkan nama item
ke objek Text kami, membuat kalimat seperti "BeastType
dibunuh,
menjatuhkan DROP_NAME
a.". Kemudian, untuk contoh ini, kita menambahkan beberapa nomor statistik kami (dalam array aStats
dan BeastDrops
).
Akhirnya, setelah 100
pengulangan, kami menampilkan statistik jumlah binatang (dari 100) yang
menjatuhkan barang-barang, dan jumlah setiap item yang dijatuhkan.
Contoh Lain: Menjatuhkan Produk Visual
Mari kita pertimbangkan contoh lain:
Tekan Space untuk menciptakan bola api yang dapat digunakan untuk membunuh musuh.
Seperti yang Anda lihat, musuh dibuat secara acak (bestiary dari 11). Karakter pemain (di sebelah kiri) dapat membuat serangan proyektil. Ketika proyektil menghantam musuh, musuh mati.
Fungsi yang digunakan
serupa dengan apa yang telah kita lihat dalam contoh sebelumnya. Fungsi dapat menentukan
apakah musuh menjatuhkan beberapa item atau tidak, dan menentukan apa saja item
tersebut. Kali ini, juga diciptakan representasi visual dari item yang dijatuhkan, dan update statistik di bagian bawah layar.
Berikut adalah implementasi dalam pseudocode:
1 |
CONSTANT ENEMY_NAME = 0 |
2 |
CONSTANT ENEMY_DROPRATE = 1 |
3 |
CONSTANT ENEMY_RARITY = 2 |
4 |
CONSTANT ENEMY_ANIM = 3 |
5 |
CONSTANT DROP_NAME = 0 |
6 |
CONSTANT DROP_RATE = 1 |
7 |
//Constants for the readability of the arrays
|
8 |
|
9 |
int EnemiesSpawned = 0 |
10 |
int EnemiesDrops = 0 |
11 |
|
12 |
array aEnemy(11,4) |
13 |
array aDrop(17,2) |
14 |
array aStats(17) |
15 |
array aTemp(0) |
16 |
|
17 |
On start of the project, we roll the data in aEnemy and aDrop |
18 |
Start Timer "Spawn" for 0.2 second |
19 |
|
20 |
Function "SpawnEnemy" |
21 |
int EnemyType = 0 |
22 |
EnemyType = random(11) //We roll an enemy type out of the 11 available |
23 |
Create object Enemy //We create the visual object Enemy on screen |
24 |
Enemy.Animation = aEnemy(EnemyType, ENEMY_ANIM) |
25 |
EnemiesSpawned = EnemiesSpawned + 1 |
26 |
txtEnemy.text = aEnemy(EnemyType, ENEMY_NAME) & " appeared" |
27 |
Enemy.Name = aEnemy(EnemyType, ENEMY_NAME) |
28 |
Enemy.Type = EnemyType |
29 |
|
30 |
Keyboard Key "Space" pressed |
31 |
Create object Projectile from Char.Position |
32 |
|
33 |
Projectile collides with Enemy |
34 |
Destroy Projectile |
35 |
Enemy start Fade |
36 |
txtEnemy.text = Enemy.Name & " has been vanquished." |
37 |
|
38 |
Enemy Fade finished |
39 |
Start Timer "Spawn" for 2.5 seconds //Once the fade out is finished, we wait 2.5 seconds before spawning a new enemy at a random position on the screen |
40 |
Function "Drop" (Enemy.Type, Enemy.X, Enemy.Y, Enemy.Name) |
41 |
|
42 |
Function Drop (EnemyType, EnemyX, EnemyY, EnemyName) |
43 |
int DropChance = 0 |
44 |
int Rarity = 0 |
45 |
DropChance = ceil(random(100)) |
46 |
Rarity = aEnemy(EnemyType, ENEMY_RARITY) |
47 |
txtEnemy.text = EnemyName & " dropped " |
48 |
|
49 |
If DropChance > aEnemy(EnemyType, ENEMY_DROPRATE) |
50 |
txtEnemy.text = txtEnemy.text & " nothing." |
51 |
//Nothing was dropped
|
52 |
If DropChance <= aEnemy(EnemyType, ENEMY_DROPRATE) |
53 |
aTemp.clear/set size to 0 |
54 |
For a = 0 to aDrop.Width |
55 |
and aDrop(a, DROP_RATE) >= Rarity |
56 |
aTemp.Push(a) //We push the current index into the aTemp array as possible drop index |
57 |
|
58 |
int DropType = 0 |
59 |
DropType = Random(aTemp.Width) //We pick what is the drop index amongst the indexes stored in aTemp |
60 |
aStats(DropType) = aStats(DropType) + 1 |
61 |
EnemiesDrops = EnemiesDrops + 1 |
62 |
Create Object Drop at EnemyX, EnemyY |
63 |
Drop.AnimationFrame = DropType |
64 |
txtEnemy.Text = txtEnemy.Text & aDrop.(DropType, DROP_NAME) & "." //We display the name of the drop |
65 |
txtStats.text = EnemiesDrops & " enemies on " & EnemiesSpawned & " dropped items." & newline |
66 |
For a = 0 to aStats.width |
67 |
and aStats(a) > 0 |
68 |
txtStats.text = txtStats.Text & aStats(a) & " " & aDrop(a, DROP_NAME) & " " |
69 |
|
70 |
Timer "Spawn" |
71 |
Call Function "SpawnEnemy" |
Lihatlah isi tabel aEnemy
dan aDrop
:
Index (X) | Name (Y-0) | Drop rate (Y-1) | Kelangkaan item (Y-2) | Nama animasi (Y-3) |
0 | Healer Female | 100 | 100 | Healer_F |
1 | Healer Male | 75 | 75 | Healer_M |
2 | Mage Female | 65 | 55 | Mage_F |
3 | Mage Male | 45 | 100 | Mage_M |
4 | Ninja Female | 15 | 15 | Ninja_F |
5 | Ninja Male | 35 | 50 | Ninja_M |
6 | Ranger Male | 75 | 80 | Ranger_M |
7 | Townfolk Female | 75 | 15 | Townfolk_F |
8 | Townfolk Male | 95 | 95 | Townfolk_M |
9 | Warrior Female | 70 | 70 | Warrior_F |
10 | Warrior Male | 45 | 55 | Warrior_M |
Index (X) | Name (Y-0) | Kelangkaan item (Y-1) |
0 | Apple | 75 |
1 | Banana | 50 |
2 | Carrot | 95 |
3 | Grape | 85 |
4 | Empty potion | 80 |
5 | Blue potion | 75 |
6 | Red potion | 70 |
7 | Green potion | 60 |
8 | Pink Heart | 65 |
9 | Blue pearl | 15 |
10 | Rock | 100 |
11 | Glove | 25 |
12 | Armor | 30 |
13 | Jewel | 35 |
14 | Mage Hat | 65 |
15 | Wood shield | 85 |
16 | Iron axe | 65 |
Berbeda dengan contoh
sebelumnya, array yang berisi data musuh bernama aEnemy
dan berisi data ENEMY_ANIM
yang merupakan nama animasi musuh. Dengan cara ini, ketika pemijahan musuh, kita dapat melihat dan mengotomatisasi tampilan grafis.
Dalam lapisan yang
sama, aDrop
sekarang berisi 16 unsur, bukan enam, dan masing-masing indeks
mengacu pada frame animasi dari objek-tapi aku bisa memiliki beberapa animasi
juga, seperti untuk musuh, jika barang jatuh harus dianimasikan .
Kali ini, ada jauh lebih banyak musuh dan item dibandingkan di contoh sebelumnya. Dapat anda lihat, data mengenai tingkat drop dan nilai-nilai kelangkaan masih ada. Salah satu perbedaan penting adalah kita telah memisahkan pemijahan musuh dari fungsi yang dpat menghitung ada penurunan atau tidak. Hal ini karena, dalam permainan nyata, musuh akan melakukan sesuatu yang lebih dari hanya menunggu untuk dibunuh!
Jadi sekarang kita
memiliki fungsi SpawnEnemy
dan fungsi Drop
lain. Penurunan sangat mirip dengan cara kita menangani "gulungan dadu" item drop
pada contoh sebelumnya, tetapi saat ini membutuhkan beberapa parameter yaitu : X dan Ymerupakan koordinat musuh di layar, karena itulah tempat di mana kita menghasilkan item ketika ada drop; parameter lainnya adalah EnemyType
, sehingga kita dapat melihat nama musuh dalam tabel aEnemy
, dan nama karakter sebagai string, untuk membuatnya lebih cepat dalam menulis umpan balik yang kami ingin berikan kepada pemain.
Logika fungsi Drop
mirip dengan contoh sebelumnya; sebagian besar perubahan adalah cara kita menampilkan umpan balik. Kali ini, bukan hanya menampilkan teks, kami juga menelurkan sebuah objek di layar untuk memberikan representasi visual kepada pemain.
(Catatan:. Untuk bertelur,
musuh berada pada beberapa posisi di layar, saya menggunakan obyek tak
terlihat, sebagai referensi, yang terus bergerak kiri dan kanan setiap kali fungsi SpawnEnemy
dipanggil, menciptakan musuh di koordinat objek Bibit
saat ini, sehingga musuh muncul dan berbagai lokasi horisontal.)
satu hal terakhir yang dibahaas yaitu kapan tepatnya fungsi Drops
dipanggil. Saya tidak mencetuskan langsung setelah kematian musuh, tapi setelah musuh telah memudar (animasi kematian musuh). Jika Anda lebih suka Anda tentu saja dapat melakukan panggilan drop ketika musuh masih terlihat di layar; sekali lagi, ini benar benar berada di game desain anda.



Kesimpulan
Pada level desain, memiliki musuh yang menjatuhkan beberapa jarahan menyebabkab pemain scara intensif akan menghadapi dan menghancurkan mereka. Item drop memberikan Anda power-up, statistik, atau bahkan gol untuk pemain, apakah dengan cara langsung atau tidak langsung.
Pada tingkat implementasi, menjatuhkan barang-barang dikelola melalui fungsi coder dengan memikirkan kapan fungsi itu dipanggil. Fungsi melakukan pekerjaan pemeriksaan kelangkaan item yang harus dijatuhkan sesuai dengan jenis musuh yang tewas, dan juga dapat menentukan tempat dimana untuk bertelur pada layar jika dan ketika diperlukan. Data untuk item dan musuh dapat diselenggarakan dalam struktur data seperti array, dan mendongak oleh fungsi.
Fungsi menggunakan nomor acak untuk menentukan frekuensi dan jenis drops, dan coder memiliki kontrol atas gulungan acak mereka, dan data itu mendonga, untuk menyesuaikan nuansa drop dalam permainan.
Saya harap Anda menikmati artikel ini dan memiliki pemahaman yang lebih baik tentang bagaimana untuk membuat monster Anda menjatuhkan loots dalam permainan Anda. Saya tak sabar untuk melihat permainan Anda menggunakan mekanik itu.
Referensi
- Image credit: Gold Treasure Icons by Clint Bellanger.
- Sprite credit: Character sprites by Antifareas.
- Sprite credit: Battle Backgrounds from Trent Gamblin.
- Sprite credit: Pixel Art Icons for RPGs from 7SoulDesign.