Pertimbangkan permainan kartu, seperti Hearthstone .
Ada ratusan kartu yang melakukan berbagai hal, beberapa di antaranya unik bahkan untuk satu kartu! Misalnya, ada kartu (disebut Nozdormu) yang mengurangi putaran pemain menjadi hanya 15 detik!
Ketika Anda memiliki berbagai macam efek potensial, bagaimana Anda menghindari angka ajaib dan cek satu kali di seluruh kode Anda? Bagaimana cara menghindari metode "Check_Nozdormu_In_Play" di kelas PlayerTurnTime? Dan bagaimana seseorang dapat mengatur kode sehingga ketika Anda menambahkan lebih banyak efek, Anda tidak perlu memperbaiki sistem inti untuk mendukung hal-hal yang belum pernah mereka dukung sebelumnya?
architecture
software-engineering
scripting
Sable Dreamer
sumber
sumber
Jawaban:
Sudahkah Anda melihat sistem komponen entitas dan strategi pengiriman pesan acara?
Efek status harus merupakan komponen dari beberapa jenis yang dapat menerapkan efek gigihnya dalam metode OnCreate (), kedaluwarsa efeknya di OnRemoved () dan berlangganan pesan acara permainan untuk menerapkan efek yang terjadi sebagai reaksi terhadap sesuatu yang terjadi.
Jika efeknya terus-menerus bersyarat (bertahan selama X berubah, tetapi hanya berlaku dalam keadaan tertentu) Anda mungkin perlu memeriksa kondisi tersebut di berbagai fase.
Kemudian, Anda hanya memastikan bahwa gim Anda tidak memiliki angka sulap standar juga. Pastikan segala sesuatu yang dapat diubah adalah variabel yang digerakkan oleh data alih-alih standar kode keras dengan variabel yang digunakan untuk pengecualian apa pun.
Dengan cara ini, Anda tidak pernah berasumsi berapa panjang belokannya. Itu selalu merupakan variabel yang selalu diperiksa yang dapat diubah oleh efek apa pun dan mungkin dibatalkan kemudian oleh efek ketika itu berakhir. Anda tidak pernah memeriksa pengecualian sebelum default ke nomor ajaib Anda.
sumber
RobStone berada di jalur yang benar, tetapi saya ingin menguraikan karena ini adalah persis apa yang saya lakukan ketika saya menulis Dungeon Ho !, seorang Roguelike yang memiliki sistem efek yang sangat kompleks untuk senjata dan mantra.
Setiap kartu harus memiliki satu set efek yang melekat padanya, didefinisikan sedemikian rupa sehingga dapat menunjukkan apa efeknya, apa yang ditargetkan, bagaimana, dan berapa lama. Misalnya, efek "kerusakan lawan" mungkin terlihat seperti ini;
Kemudian, ketika efek kebakaran, miliki rutin generik menangani pemrosesan efek. Seperti orang idiot, saya menggunakan pernyataan case / switch yang sangat besar:
Tetapi cara yang jauh lebih baik dan lebih modular untuk melakukannya adalah melalui polimorfisme. Buat kelas Efek yang membungkus semua data ini, buat subkelas untuk setiap jenis efek, dan kemudian minta kelas itu menimpa metode onExecute () yang khusus untuk kelas tersebut.
Jadi kita akan memiliki kelas Efek dasar, lalu kelas DamageEffect dengan metode onExecute (), jadi dalam kode pemrosesan kami, kami hanya akan pergi;
Cara untuk berurusan dengan mengetahui apa yang sedang dimainkan adalah dengan membuat Vector / Array / daftar tertaut / etc. efek aktif (dari tipe Efek, kelas dasar) yang melekat pada objek apa pun (termasuk playfield / "game"), jadi alih-alih harus memeriksa apakah efek tertentu sedang dimainkan, Anda cukup mengulangi semua efek yang melekat pada objek dan biarkan mereka mengeksekusi. Jika suatu efek tidak dilampirkan ke suatu objek, itu tidak dalam permainan.
sumber
Saya akan menawarkan beberapa saran. Beberapa dari mereka saling bertentangan. Tapi mungkin ada yang bermanfaat.
Pertimbangkan daftar versus bendera
Anda dapat mengulangi dunia dan memeriksa bendera pada setiap item untuk memutuskan apakah akan melakukan hal bendera. Atau Anda dapat menyimpan daftar hanya barang-barang yang harus melakukan hal bendera.
Pertimbangkan daftar & enumerasi
Anda dapat terus menambahkan bidang boolean ke kelas item Anda, isAThis dan isAThat. Atau Anda dapat memiliki daftar elemen string atau enum, seperti {"isAThis", "isAThat"} atau {IS_A_THIS, IS_A_THAT}. Dengan begitu Anda bisa menambahkan yang baru di enumerasi (atau string const) tanpa menambahkan bidang. Bukannya ada yang salah dengan menambahkan bidang ...
Pertimbangkan fungsi pointer
Alih-alih daftar bendera atau enum, bisa memiliki daftar tindakan untuk mengeksekusi untuk item itu dalam konteks yang berbeda. (Entitas-ish ...)
Pertimbangkan benda
Beberapa orang lebih suka pendekatan berbasis entitas data, atau skrip, atau komponen. Tapi hierarki benda kuno juga patut dipertimbangkan. Kelas dasar perlu menerima tindakan, seperti "mainkan kartu ini untuk fase-B" atau apa pun. Kemudian setiap jenis kartu dapat menimpa dan merespons sebagaimana mestinya. Mungkin ada objek pemain dan objek game juga, sehingga game dapat melakukan hal-hal seperti, if (player-> isowedToPlay ()) {do the play…}.
Pertimbangkan kemampuan debug
Satu hal yang menyenangkan tentang setumpuk bidang bendera adalah Anda dapat memeriksa & mencetak kondisi setiap item dengan cara yang sama. Jika keadaan diwakili oleh berbagai jenis, atau kantong komponen, atau pointer fungsi, atau berada di daftar yang berbeda, mungkin tidak cukup hanya dengan melihat bidang item. Ini semua kompromi.
Akhirnya, refactoring: Pertimbangkan tes unit
Tidak peduli seberapa besar Anda menggeneralisasikan arsitektur Anda, Anda akan dapat membayangkan hal-hal yang tidak tercakup. Maka Anda harus refactor. Mungkin sedikit, mungkin banyak.
Cara untuk membuat ini lebih aman adalah dengan tes unit. Dengan begitu Anda dapat yakin bahwa meskipun Anda menata ulang hal-hal di bawahnya (mungkin banyak!), Fungsionalitas yang ada masih berfungsi. Setiap unit tes terlihat, secara umum, seperti ini:
Seperti yang Anda lihat, menjaga agar panggilan API tingkat atas agar game (atau pemain, kartu, & c) tetap stabil adalah kunci strategi pengujian unit.
sumber
Alih-alih memikirkan setiap kartu secara individual, mulailah berpikir dalam hal kategori efek, dan kartu mengandung satu atau lebih dari kategori ini. Misalnya, untuk menghitung jumlah waktu dalam satu belokan, Anda dapat mengulangi semua kartu yang sedang dimainkan dan memeriksa kategori "memanipulasi durasi giliran" dari setiap kartu yang berisi kategori itu. Setiap kartu kemudian menambah atau menimpa durasi giliran berdasarkan aturan yang Anda putuskan.
Ini pada dasarnya adalah sistem komponen mini, di mana setiap objek "kartu" hanyalah sebuah wadah untuk sekelompok komponen efek.
sumber