
Saat mendesain game multipemain, hampir komponen terpenting adalah keseimbangan. Karya seorang desainer game dalam hal ini mirip dengan karya seorang analis intelijen: jika ia bekerja dengan baik, tidak ada yang memperhatikan. Ini layak tersandung, dan para pemain tanpa malu mengambil keuntungan dari kesalahan. Tetapi hal yang paling menarik terjadi ketika, selain desainer game, programmer juga keliru ...
Pada artikel ini, kami akan mempertimbangkan satu elemen dari strategi Cossack 3 . Gim ini berisi berbagai jenis musketeer dan penembak lainnya pada abad ke-17 dan ke-18, serta peluang untuk mengeksplorasi teknologi yang mengurangi waktu pengisian ulang senapan. Ada dua peningkatan total, yang masing-masing membawa + 30% ke tingkat api - menurut antarmuka game.
Tetapi bahkan dengan melihat jelas bahwa beberapa unit tempur, setelah meneliti perbaikan, menembak tidak hanya pada 60%, tetapi bahkan beberapa kali lebih sering. Saat mengukur laju tembakan langsung menggunakan timer game bawaan, angka yang benar-benar aneh keluar yang tidak ada hubungannya dengan persentase yang dinyatakan.
Di bawah tenda "Cossack"
Untungnya, gim ini dibuat dengan cara yang sangat ramah untuk para modder, jadi semua skrip yang kita butuhkan tersedia sebagai file teks dalam data / skrip / folder. Dilihat oleh sintaks, skrip ditulis dalam Delphi atau dalam bahasa yang sangat mirip. Mari kita lihat mekanisme penghitungan interval antara pemotretan.
Catatan- Analisis dilakukan pada game "Cossacks 3" versi 2.1.4.
- Semua bagian skrip di bawah ini berisi kodesemu yang disederhanakan.
Ketika permainan dimulai, semua unit tempur diinisialisasi. Prosedur menunjukkan nilai-nilai vitalitas, biaya dan senjata untuk setiap jenis. Untuk senjata ringan, parameter dilewatkan yang menunjukkan interval antara tembakan dalam bingkai game:
//lib/unit.script procedure _unit_InitBase() 'musketeer' : maxhp := 70; SetObjBaseWeapon( x,x,x,x, 150, ... ); SetObjBasePrice( ... ); //lib/unit.script procedure SetObjBaseWeapon( x,x,x,x, pause, ... ) weapon.pause := _misc_FramesToTime( pause );
Dilihat oleh komentar, satuan waktu "kerangka permainan" adalah atavisme dari "Cossack" pertama, proses permainan yang disalin ketika membuat bagian ketiga. Namun, frame segera dihitung dalam detik permainan dengan rasio 1:32, dan kami tidak menjumpainya lagi:
//lib/misc.script function _misc_FramesToTime( val ) Result := ( val * gc_frames_to_time ); //dmscript.global gc_frames_to_time := 0.03125; gc_time_to_frames := 32;
Juga, pada awal permainan, data negara-negara game diinisialisasi, termasuk perbaikan yang tersedia. Untuk masing-masing dari mereka, variabel nilai ditunjukkan dan disimpan, yang, ketika mempelajari perbaikan ini, mempengaruhi perhitungan ulang dari parameter yang diperlukan dari permainan:
//lib/country.script procedure _country_Init() _country_AddUpgrade( x,x,x,x, type_attpauseperc, -30, ... ); procedure _country_AddUpgrade( x,x,x,x, upgrade_type, value, ... );
Dalam kasus kami, ini berarti bahwa interval unit militer setelah setiap peningkatan dikalikan dengan 0,7 dan kemudian ... dibulatkan ?!
//lib/player.script procedure _player_ApplyUpgrade() type_attpauseperc : weapon.pause := Round( weapon.pause * (1 + value/100) );
Mengingat fakta bahwa awalnya interval penembak adalah angka floating point dalam kisaran dari 3,125 ke 5.0, keputusan untuk mengakhiri hasil perhitungan ulang terlihat agak aneh, jika tidak penting.
Setelah setiap tembakan, penundaan sebelum tembakan berikutnya diindikasikan. Pengubah idividual.attackrate diterapkan pada struktur menara dan dalam kasus kami selalu 1.
Jadi, selain kesalahan matematis dalam perhitungan, detail yang dapat dibaca di bawah spoiler di bawah ini, ada pembulatan yang tidak tepat dari angka floating-point. Saya bertanya-tanya apa efeknya pada mekanisme permainan yang memiliki sedikit pengawasan pada pandangan pertama?
Sedikit matematikaTingkat kebakaran berbanding terbalik dengan ukuran interval antara tembakan. Dan jika itu adalah jumlah putaran per menit yang penting bagi pemain, maka mesin permainan, sebagai aturan, menggunakan interval untuk menghitung jeda. Tangkapan di sini adalah bahwa "mengurangi interval sebesar 30%" dan "meningkatkan laju api sebesar 30%" adalah hal yang sama sekali berbeda. Rasio r antara interval t dan jumlah tembakan n dijelaskan oleh rumus sederhana:
Misalnya, jika kita mengambil interval 6 detik (10 putaran per menit) dan menguranginya hingga 30%, maka kita tidak akan mendapatkan 13 putaran per menit:
Untuk mendapatkan nilai yang diinginkan, Anda harus membagi interval saat ini dengan rasio yang diinginkan dari laju api baru ke yang lama:
Metode pengukuranUntuk mendapatkan nilai yang bekerja dengan mesin game, Anda dapat menggunakan fungsi logging. Untuk melakukan ini, Anda harus mengaktifkan pencatatan terlebih dahulu:
//cossacks.ini & editor.ini LogFileEnabled = true LogFileRoot = true
Dan kemudian tambahkan di akhir prosedur _unit_ApplyAttackPause () panggilan ke fungsi Log () :
//data/scripts/lib/unit.script procedure _unit_ApplyAttackPause(const goHnd, weapind : Integer); begin //... if (attpause<>0) then Log(TObjProp(pobjprop).sid+' '+FloatToStr(attpause)); end;
Sekarang Anda dapat bermain-main dengan berbagai panah dan peningkatan pada editor peta (untuk mengaktifkan mode serangan, tekan Ctrl + W ). Protokol akan ditulis ke file teks di folder / log . Setelah setiap tembakan, pengidentifikasi unit tempur dan nilai interval saat ini akan dicatat.
Siapa itu siapa?
Awalnya, skrip game membedakan antara 35 jenis penembak (tidak termasuk tentara bayaran yang tidak terpengaruh oleh peningkatan). Jika kita mengelompokkan semuanya berdasarkan ukuran interval, maka kita dapat membedakan sepuluh kategori. Saya memutuskan untuk menyortirnya dengan peningkatan relatif tingkat api untuk memilih penembak yang paling diuntungkan dari peningkatan. Jadi, hasil analisis:
| Interval serangan | Tembakan / mnt | Tingkat api |
Kategori Perangkat tambahan | 0 | +1 | +2 | 0 | +1 | +2 | +1 | +2 |
Saya | 5.00 | 4.0 | 3.0 | 12.0 | 15 | 20 | + 25% | + 67% |
II | 6.88 | 5,0 | 4.0 | 8.7 | 12 | 15 | + 38% | + 72% |
III | 5.31 | 4.0 | 3.0 | 11.3 | 15 | 20 | + 33% | + 77% |
IV | 5.63 | 4.0 | 3.0 | 10.7 | 15 | 20 | + 41% | + 88% |
V | 3,75 | 3.0 | 2.0 | 16.0 | 20 | 30 | + 25% | + 88% |
VI | 5.94 | 4.0 | 3.0 | 10.1 | 15 | 20 | + 48% | + 98% |
VII | 4.06 | 3.0 | 2.0 | 14.8 | 20 | 30 | + 35% | + 103% |
VIII | 4.38 | 3.0 | 2.0 | 13.7 | 20 | 30 | + 46% | + 119% |
IX | 4.69 | 3.0 | 2.0 | 12.8 | 20 | 30 | + 56% | + 134% |
X | 3.13 | 2.0 | 1,0 | 19,2 | 30 | 60 | + 56% | + 213% |
Dalam diagram di bawah ini, kolom tersebut sesuai dengan kategori I - X, dari kiri ke kanan. Kolom putus-putus terakhir dari diagram sesuai dengan tingkat kenaikan yang dinyatakan dalam antarmuka game. Kelompok kolom kiri menunjukkan peningkatan laju kebakaran setelah satu peningkatan, kanan - setelah keduanya. 
Daftar kategori dan unitPermainan ini memiliki berbagai negara - 17 Eropa dan empat unik (Ukraina, Turki, Aljazair, dan Skotlandia). Faksi-faksi Eropa sangat mirip sejak awal dan memiliki penembak dan naga di abad 17 dan 18, serta para granat. Tetapi kadang-kadang panah dari beberapa negara berbeda dari templat, atau sepenuhnya diganti oleh jenis yang unik.
Kategori | Unit tempur |
---|
Saya | Musketeer abad ke-17 (Austria) Szekej (Hongaria) Penembak Skotlandia (Inggris) Persemakmuran Polandia-Lituania (Polandia) Dragoon abad ke-18 (Belanda dan Piedmont) |
II | Huntsman (Swiss) Royal Musketeer (Prancis) |
III | Grenadier (Eropa kecuali Denmark dan Prusia) Dragoon abad ke-18 (Eropa kecuali Perancis, Belanda dan Piedmont) Kavaleri ringan (berbagai negara) |
IV | Dragoon abad ke-17 (Eropa) |
V | Musketeer abad ke-17 (Belanda) |
VI | Musketeer abad ke-17 (Spanyol) Musketeer abad ke-18 (Bavaria dan Denmark) Grenadier (Denmark) Relawan (Portugal) Huntsman (Prancis) |
VII | Serdyuk (Ukraina) |
VIII | Musketeer abad ke-18 (Saxony) Grenadier (Prusia) |
IX | Musketeer abad ke-17 (Eropa kecuali Austria, Polandia, Belanda dan Spanyol) Musketeer Covenant (Skotlandia) Sagitarius (Rusia) Janissar (Turki) Musketeer abad ke-18 (Eropa kecuali Denmark, Bavaria, dan Saxony) Pandur (Austria) Dragoon abad ke-18 (Prancis) |
X | Musketeer abad ke-17 (Polandia) Hajduk (Hongaria) |
Catatan:
- Nama-nama unit militer disalin dari antarmuka Rusia permainan.
- Panah dalam huruf miring abad ke-18 ada dalam huruf miring .
- Panah kuda disorot dalam huruf tebal .
Ternyata musketeer Polandia abad ke-17 dan pembajak Hungaria menang paling banyak dari peningkatan laju tembakan: alih-alih +60% yang dijanjikan, mereka menembak lebih dari tiga kali lebih sering. Karena nilai awal interval yang rendah, mereka akhirnya menembak lebih cepat daripada semua penembak lainnya dua, tiga, atau bahkan empat kali.
Di antara kavaleri, kapal perang Prancis abad ke-18 paling baik diselesaikan: mereka menerima laju tembakan lebih dari dua kali lipat. Akibatnya, mereka menembakkan 50% lebih banyak tembakan per menit daripada rekan-rekan mereka dari negara-negara Eropa lainnya.
Secara alami, kerusakan tembakan atau kerusakan per detik tidak diperhitungkan di sini, tetapi bahkan tanpa data ini jelas bahwa unit militer tidak berperilaku sebagaimana dimaksud.
Bagaimana cara memperbaikinyaSolusi tercepat dan non-invasif untuk masalah ini adalah menulis ulang formula untuk menerapkan perbaikan. Selain menolak pembulatan, alih-alih mengalikan interval dengan 0,3, bagilah dengan 1,3. Untuk melakukan ini, cukup ganti formula dengan prosedur perbaikan gc_upg_type_attpauseperc dengan
//lib/player.script Round(weapon.pause*(1+value/100));
pada
weapon.pause/(1+(-value)/100);
Karena perbaikan diterapkan secara konsisten, pada akhirnya, alih-alih menyatakan + 60%, kami mendapatkan + 69%. Tapi itu masih lebih baik dari + 213%.
Kata penutup
Untuk mengidentifikasi secara salah perhitungan dalam keseimbangan dalam kasus ini, dua aspek lagi dari mekanisme permainan harus dianalisis - kerusakan penembak dan nilai ekonomi bersama dengan waktu yang dibutuhkan untuk membuat unit tempur. Namun, akal sehat memberi tahu Anda untuk menunggu pembaruan berikutnya terlebih dahulu ...
Saya mendapat ide untuk penelitian dari video " Mengapa Tingkat Serangan di AoE2 Sering Salah ", yang membahas masalah serupa dalam strategi Age of Empires II .
UPD: Kesalahan sebagian diperbaiki
Tidak bahkan satu minggu telah berlalu sejak publikasi artikel, karena pengembang dalam pembaruan 2.2.1 memperbaiki kesalahan dengan pembulatan. Pada saat yang sama, formula itu sendiri tetap sama - laju kebakaran tumbuh pada 43% per peningkatan. Karena perhitungannya bersifat inkremental, setelah memeriksa kedua peningkatan, semua panah bekerja 104% lebih cepat.
MejaTingkat unit api dalam tembakan per menit setelah meneliti kedua peningkatan, dalam urutan yang meningkat:
Unit tempur | Tembakan |
---|
Huntsman (Swiss) Royal Musketeer (Prancis) | 17.8 |
Musketeer abad ke-17 (Spanyol) Musketeer abad ke-18 (Bavaria dan Denmark) Grenadier (Denmark) Relawan (Portugal) Huntsman (Prancis) | 20.6 |
Dragoon abad ke-17 (Eropa) | 21.8 |
Grenadier (Eropa kecuali Denmark dan Prusia) Dragoon abad ke-18 (Eropa kecuali Perancis, Belanda dan Piedmont) Kavaleri ringan (berbagai negara) | 23.0 |
Musketeer abad ke-17 (Austria) Szekej (Hongaria) Penembak Skotlandia (Inggris) Polandia - Persemakmuran Lithuania (Polandia) Dragoon abad ke-18 (Belanda dan Piedmont) | 24.5 |
Musketeer abad ke-17 (Eropa kecuali Austria, Polandia, Belanda dan Spanyol) Musketeer Covenant (Skotlandia) Sagitarius (Rusia) Janissar (Turki) Musketeer abad ke-18 (Eropa kecuali Denmark, Bavaria, dan Saxony) Pandur (Austria) Dragoon abad ke-18 (Prancis) | 26.1 |
Musketeer abad ke-18 (Saxony) Grenadier (Prusia) | 28.0 |
Serdyuk (Ukraina) | 30.1 |
Musketeer abad ke-17 (Belanda) | 32,7 |
Musketeer abad ke-17 (Polandia) Hajduk (Hongaria) | 39,2 |