Dynamic indexing adalah teknik yang digunakan untuk memastikan spell atau kodemu dapat digunakan lebih dari satu kali tanpa gangguan. Pada pertama, ini sangat menakutkan untuk dilihat. Tutorial ini bertujuan untuk menunjukkannya dengan lebih mudah: memudahkan yang rumit.
Sebelum kita mulai Dynamic Indexing, kamu harus mengerti tujuannya. Tujuan utama adalah mencapai MUI, tujuan semua pembuat spell yang tidak gagal harus berharap untuk didapat.
MUI MUI adalah singkatan dari Multiple Unit Instanceability. Yang tujuan satu-satunya: membuat spell dapat digunakan oleh lebih dari 1 unit (tanpa kejadian yang tidak diinginkan).
Apa masalah-masalah MUI yang saya bicarakan? Ya, Mari membuat spell mudah yang mengirim health point setiap 0.1 detik.
Terlihat cukup mudah. Kamu akan memulai sebuah timer saat spell mulai melakukan loop/putaran setiap 0.1 detik. Dalam putaran tersebut, kamu akan melakukan damage pada target untuk 2 hit points, dan memberikan 2 hit points kepada Caster:
Code
Siphon Life Cast Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Siphon Life Actions Set SL_Caster = (Triggering unit) Set SL_Target = (Target unit of ability being cast) Set SL_Counter = 0 Trigger - Turn on Siphon Life Loop <gen>
Code
Siphon Life Loop Events Time - Every 0.10 seconds of game time Conditions Actions Unit - Cause SL_Caster to damage SL_Target, dealing 2 damage of attack type Spells and damage type Normal Unit - Set life of SL_Caster to ((Life of SL_Caster) + 2.00) Set SL_Counter = (SL_Counter + 0.10) If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Counter Greater than or equal to 3.00 Then - Actions Trigger - Turn off (This trigger) Else - Actions
Ini akan bekerja (abaikan fakta bahwa ini tidak mengecek jika unit telah mati).
(Lingkaran disebelah kanan bawah menunjukkan berapa lama waktu telah berlalu)
Tapi apa yang kamu pikirkan jika ada caster lain datang?
Sekarang caster pertama tidak akan mendapat HP lagi, dan monster hanya menerima 2 damage per detik daripada 4 (2 + 2). Kenapa? Lihat pada trigger diatas. Saat spell digunakan, SL_Caster diatur menggunakan casting unit. Karena variable hanya bisa menunjukkan satu hal setiap kali, caster asli (hijau) tertimpa. tidak hanya itu, tapi targetnya juga tertimpa, dan SL_Counter direset ke 0.
Ini menunjukkan kenapa kita perlu MUI. Tanpa itu, monster tidak mengalami rasa sakit sebanyak yang seharusnya.
Dynamic Indexing Ada banyak cara untuk mencapai MUI. Dynamic indexing adalah salah satunya. Itu melibatkan array dan satu index setiap spell cast.
Hal pertama yang harus dilakukan adalah mengetahui variable apa yang kamu perlukan untuk disimpan. Pada kali ini, kita perlu menyimpan: Caster: unit Target: unit Counter: real Kenapa? Karena variable-variable tersebut kita gunakan di periodic loop. Simpan variable yang hanya kamu perlukan untuk diakses selama periodic. Jika kamu hanya butuh data saat spell digunakan pada pertama kali, kamu tidak perlu menyimpannya.
Daripada membuat variable tunggal, kita akan mengubahnya menjadi array:
Sekarang, tujuan dari dynamic indexing adalah untuk memiliki satu index untuk setiap spell cast. Di periodic trigger, kamu akan memutar melewati setiap spell cast yang aktif (diketahui sebagai instansi dari spell). Instansi biasanya menunjukkan pada satu spell cast, dan itu akan diasosiasikan dengan index yang digunakan. Instansi pertama dari sebuah spell akan memiliki index yaitu 1, yang kedua akan memiliki index yaitu 2. Saat kita bicara tentang multi-instanceability, kita sebenarnya mengatakan bahwa spell harus bekerja dengan penggunaan spell lebih dari satu kali pada saat bersamaan.
Sebagai contoh, jika kamu memiliki 3 instansi spell, itu akan terlihat seperti ini:
Saat kamu memutar melewati setiap instansi, kamu akan memiliki caster dan target yang berbeda untuk dihadapi. inilah beberapa kode semu:
Code
For each (SL_Loop_Integer) from 1 to 3, do (Actions) Loop - Actions Unit - Cause SL_Caster[SL_Loop_Integer] to damage SL_Target[SL_Loop_Integer], dealing 2 damage of attack type Spells and damage type Normal Unit - Set life of SL_Caster[SL_Loop_Integer] to ((Life of SL_Caster[SL_Loop_Integer]) + 2.00) Set SL_Counter[SL_Loop_Integer] = (SL_Counter[SL_Loop_Integer] + 0.10)
Perhatikan bahwa setiap kali putaran mengulang, itu menunjukkan pada instansi baru. Saat SL_Loop_Integer adalah 1, itu akan menunjukkan pada instansi pertama (lihat gambaar diatas). Saat SL_Loop_Integer adalah 2, itu akan menunjukkan pada instansi kedua. Sama untuk yang ketiga.
Sekarang, kode tersebut adalah spesifik. Itu berputar melewati 3 instansi saja. Tapi bagaimana jika kita mau 5? atau 10? atau hanya 1? Tujuan utama dari dynamic indexing adalah untuk membuat bentuk umum yang dapat bekerja dalam situasi apapun. Bagaimana kita melakukannya? Mudah, kita hanya akan membuat variable dengan tipe integer untuk melacak setiap instansi:
Jadi bagaimana kita melakukannya? Ya, pertama kita harus khawatir tentang alokasi. Alokasi adalah sebuah proses untuk mendapatkan index baru dan mendaftarkan variable yang kita butuhkan. Karena kita punya urutan dari 1, 2, 3, dll.. kita hanya perlu untuk menambah index setiap kali sebuah spell digunakan.
Anggap saja kita mengikuti skenario. Spell tersebut digunakan oleh dark ranger kepada hawk, blood mage kepada pit lord, firelord kepada skeleton, dan sea witch kepada clockwerk goblin:
Gambar diatas akan menunjukkan bagaimana itu seharusnya terlihat pada alokasi. Saat spell digunakan oleh dark ranger, index seharusnya menjadi 1. SL_Caster[1] seharusnya adalah dark ranger. SL_Target[1] seharusnya adalah hawk. SL_Counter[1] seharusnya adalah 0.0. Dan seterusnya dengan index yang lain. Ini triggernya:
Code
Siphon Life Cast Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Siphon Life Actions Set SL_Index = SL_Index + 1 Set SL_Caster[SL_Index] = (Triggering unit) Set SL_Target[SL_Index] = (Target unit of ability being cast) Set SL_Counter[SL_Index] = 0 If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Index Equal to 1 Then - Actions Trigger - Turn on Siphon Life Loop <gen> Else - Actions
Ini akan bekerja. SL_Index akan bertambah 1 dari setiap instansi, dan array akan diatur untuk instansi tertentu. Untuk Index 1, caster akan menjadi dark ranger, target akan menjadi hawk, dan counter akan menjadi 0. Sama untuk setiap instansi, seperti yang ditunjukkan oleh gambar diatas.
Bagaimana dengan loop/putaran yang sebenarnya? Sama saja seperti yang kita lakukan di atas, tetapi daripada memutar ke 3, kita hanya akan memutar pada SL_Index. Kenapa? Kalu kamu pikir-pikir, SL_Index sebenarnya terus melacak jumlah dari instansi setiap spell. Saat spell pertama digunakan, index diatur ke 1. Saat yang kedua digunakan, index adalah 2. Saat yang keempat digunakan, index adalah 4. dll.
Untuk garis terakhir, itu akan menghidupkan putaran periodic/periodic loop saat instansi pertama dibuat. Kamu mungkin bertanya-tanya kenapa? Saya tidak menghidupkannya dari pertama–jangan khawatir tentang itu. Itu akan menjadi penting nanti. Sekarang kita akan melanjutkan pada looping/putaran.
(Trigger ini harus dalam keadaan off dari pertama)
Code
Siphon Life Loop Events Time - Every 0.10 seconds of game time Conditions Actions For each (SL_Loop_Integer) from 1 to SL_Index, do (Actions) Loop - Actions Unit - Cause SL_Caster[SL_Loop_Integer] to damage SL_Target[SL_Loop_Integer], dealing 2 damage of attack type Spells and damage type Normal Unit - Set life of SL_Caster[SL_Loop_Integer] to ((Life of SL_Caster[SL_Loop_Integer]) + 2.00) Set SL_Counter[SL_Loop_Integer] = (SL_Counter[SL_Loop_Integer] + 0.10) If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Counter[SL_Loop_Integer] Greater than or equal to 3.00 Then - Actions Else - Actions
Ayo analisis trigger tadi. SL_Loop_Integer hanya variable integer yang digunakan untuk looping/putaran, daripada (Integer A). Itu berputar sampai SL_Index, sebenarnya melewati setiap instansi sampai yang terakhir. SL_Caster[SL_Loop_Integer] akan menjadi caster untuk instansi tersebut. Sama untuk variable yang lain. Trigger itu akan berputar melewati instansi dan melakukan action untuk setiap instansi spell.
Kamu mungkin bertanya-tanya kenapa aku membiarkan "Then" action kosong. Apa yang kita lakukan saat spell telah selesai? Kita harus deallocate instansinya. Sebaliknya, spell akan terus berjalan pada instansi yang selesai tanpa gunanya. Itu juga akan memastikan bahwa SL_Index tidak akan bertambah terus dan terus (max array index adalah 8191). Jadi bagaimana kita melakukannya? Kita akan menimpa instansi-untuk-dihapus dengan instansi terakhir, dan kemudian kita atur loop/putarannya dan SL_Index kembali ke-1 (jadi itu akan menjalankan instansi tersebut). Inilah bagaimana akan terlihat:
Seperti yang kamu lihat, blood mage menyelesaikan spellnya (untuk sekarang). Jadi sekarang sea witch harus menggantikan tempatnya. Tujuan kita: buat sea witch memiliki index 2 (menimpa blood mage). kemudian mengurangi index dan mengulanginya (SL_Loop_Index) dengan 1. Seperti inilah bagaimana itu akan terlihat:
Code
Siphon Life Loop Events Time - Every 0.10 seconds of game time Conditions Actions For each (SL_Loop_Integer) from 1 to SL_Index, do (Actions) Loop - Actions Unit - Cause SL_Caster[SL_Loop_Integer] to damage SL_Target[SL_Loop_Integer], dealing 2 damage of attack type Spells and damage type Normal Unit - Set life of SL_Caster[SL_Loop_Integer] to ((Life of SL_Caster[SL_Loop_Integer]) + 2.00) Set SL_Counter[SL_Loop_Integer] = (SL_Counter[SL_Loop_Integer] + 0.10) If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Counter[SL_Loop_Integer] Greater than or equal to 3.00 Then - Actions Set SL_Caster[SL_Loop_Integer] = SL_Caster[SL_Index] Set SL_Target[SL_Loop_Integer] = SL_Target[SL_Index] Set SL_Counter[SL_Loop_Integer] = SL_Counter[SL_Index] Set SL_Index = (SL_Index - 1) Set SL_Loop_Integer = (SL_Loop_Integer - 1) Else - Actions
Secara visual, inilah bagaimana itu akan terlihat saat menimpa instansi milik blood mage:
Begitulah. Tapi bagaimana tentang mengurangi index dan loop integer? Kenapa kita melakukannya? Baiklah, ini bagaimana itu seharusnya terlihat setelah kita menimpa instansi kedua:
Sekarang kita sudah menimpa slot kedua, kita harus mengurangi SL_Index karena kita tidak membutuhkan instansi ke-4. SL_Index = SL_Index - 1, Yang berarti: 4 - 1 = 3. Ini bagaimana itu akan terlihat:
Sekarang masalah instansi ke-2 telah selesai! Sea witch tidak akan pernah mendapat giliran! Berarti, kita harus mengatur SL_Loop_Integer kembali agar instansi Sea witch dapat berjalan:
Akhirnya, Kita selesai! Spell akan bekerja dengan benar. Jika kamu menggunakan spell lain, Index akan mengambil slot ke-4, yang tidak memiliki masalah. Sekarang spell bekerja, tapi adalah satu hal lagi yang dapat kita lakukan untuk efisiensi. Jika tidak ada instansi aktif, kita harus mematikan trigger. Sebaliknya itu akan berputar tanpa habis. Inilah trigger terakhir:
Code
Siphon Life Cast Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Siphon Life Actions Set SL_Index = SL_Index + 1 Set SL_Caster[SL_Index] = (Triggering unit) Set SL_Target[SL_Index] = (Target unit of ability being cast) Set SL_Counter[SL_Index] = 0 If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Index Equal to 1 Then - Actions Trigger - Turn on Siphon Life Loop <gen> Else - Actions
Code
Siphon Life Loop Events Time - Every 0.10 seconds of game time Conditions Actions For each (SL_Loop_Integer) from 1 to SL_Index, do (Actions) Loop - Actions Unit - Cause SL_Caster[SL_Loop_Integer] to damage SL_Target[SL_Loop_Integer], dealing 2 damage of attack type Spells and damage type Normal Unit - Set life of SL_Caster[SL_Loop_Integer] to ((Life of SL_Caster[SL_Loop_Integer]) + 2.00) Set SL_Counter[SL_Loop_Integer] = (SL_Counter[SL_Loop_Integer] + 0.10) If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Counter[SL_Loop_Integer] Greater than or equal to 3.00 Then - Actions Set SL_Caster[SL_Loop_Integer] = SL_Caster[SL_Index] Set SL_Target[SL_Loop_Integer] = SL_Target[SL_Index] Set SL_Counter[SL_Loop_Integer] = SL_Counter[SL_Index] Set SL_Index = (SL_Index - 1) Set SL_Loop_Integer = (SL_Loop_Integer - 1) If (All Conditions are True) then do (Then Actions) else do (Else actions) If - Conditions SL_Index Equal to 0 Then - Actions Trigger - Turn off (This trigger) Else - Actions Else - Actions
Selesai!
Perbandingan Banyak orang bertanya bagaimana dynamic indexing dibandingkan dengan metode lainnya. Hal yang terpenting untuk diingat bahwa ini hanya berbeda nanodetik dan dapat bervariasi dari situasi ke situasi, tapi secara umum:
Alokasi sering lebih cepat daripada menyimpan semua item di hashtable. (array set vs. hash set)Pengulangan lebih cepat daripada hashtable/putaran unit-group (array load vs. hash load)Dealokasi bervariasi. Hashtables bisa kadang-kadang lebih cepat saat dealokasi karena dealokasi dynamic indexing sedang OnVersus struct linked list, alokasi lebih cepat. Pengulangan secara relatif sama.Dealokasi hampir selalu lebih lamban.
Ingat bahwa ini hanya perbandingan dari metode-metode, masih banyak faktor lain yang dapat mengubah kecepatan.
Credits
Hanky - memopulerkan metode ini dengan ini.Sellenisko - Banshee Queen model. :DGhostwolf - Model viewer.Classic BattleNet - Beberapa Gambar.WoW - Model Babi.