Saya sedang berpikir tentang bagaimana menerapkan status game ke dalam game saya. Hal utama yang saya inginkan adalah:
Keadaan semi-transparan top-mampu melihat melalui menu jeda ke permainan di belakang
Sesuatu OO-Saya menemukan ini lebih mudah untuk digunakan dan memahami teori di belakang, serta menjaga orgranised dan menambahkan lebih banyak.
Saya berencana menggunakan daftar tertaut, dan memperlakukannya sebagai tumpukan. Ini berarti saya dapat mengakses keadaan di bawah ini untuk semi transparansi.
Paket: Buat tumpukan negara menjadi daftar pointer yang terhubung ke IGameStates. Negara bagian atas menangani perintah pembaruan dan inputnya sendiri, dan kemudian memiliki anggota isTransparent untuk memutuskan apakah keadaan di bawahnya harus dibuat.
Maka saya bisa melakukan:
states.push_back(new MainMenuState());
states.push_back(new OptionsMenuState());
states.pop_front();
Untuk mewakili pemuatan pemain, lalu pergi ke opsi, dan kemudian menu utama.
Apakah ini ide yang bagus, atau ...? Haruskah saya melihat sesuatu yang lain?
Terima kasih.
sumber
new
dengan cara yang ditunjukkan dalam kode sampel, itu hanya meminta kebocoran memori atau kesalahan lain yang lebih serius.Jawaban:
Saya bekerja pada mesin yang sama dengan coderanger. Saya memiliki sudut pandang yang berbeda. :)
Pertama, kami tidak memiliki setumpuk FSM - kami memiliki setumpuk status. Setumpuk negara membuat FSM tunggal. Saya tidak tahu akan seperti apa tumpukan FSM. Mungkin terlalu rumit untuk melakukan sesuatu yang praktis.
Masalah terbesar saya dengan Mesin Negara Global kami adalah bahwa itu adalah tumpukan negara, dan bukan satu set negara. Ini berarti, misalnya, ... / MainMenu / Memuat berbeda dari ... / Memuat / MainMenu, tergantung pada apakah Anda mendapatkan menu utama sebelum atau setelah layar pemuatan (permainan asinkron dan memuat sebagian besar didorong oleh server ).
Sebagai dua contoh hal ini menjadikannya jelek:
Meskipun namanya, itu tidak terlalu "global". Sebagian besar sistem permainan internal tidak menggunakannya untuk melacak keadaan internal mereka, karena mereka tidak ingin keadaan mereka bercanda dengan sistem lain. Lainnya, misalnya sistem UI, dapat menggunakannya tetapi hanya untuk menyalin negara ke sistem negara setempat mereka sendiri. (Saya akan sangat berhati-hati terhadap sistem untuk negara UI. Keadaan UI bukan tumpukan, itu benar-benar DAG, dan mencoba untuk memaksa struktur lain di atasnya hanya akan membuat UI yang frustasi untuk digunakan.)
Apa yang baik untuk itu adalah mengisolasi tugas untuk mengintegrasikan kode dari pemrogram infrastruktur yang tidak tahu bagaimana alur permainan sebenarnya terstruktur, sehingga Anda bisa memberi tahu orang yang menulis patcher "masukkan kode Anda di Client_Patch_Update", dan orang yang menulis grafik memuat "masukkan kode Anda di Client_MapTransfer_OnEnter", dan kami dapat menukar logika tertentu tanpa masalah.
Pada proyek sampingan, saya lebih beruntung dengan set keadaan daripada tumpukan , tidak takut untuk membuat beberapa mesin untuk sistem yang tidak terkait, dan menolak untuk membiarkan diri saya jatuh ke dalam perangkap memiliki "negara global", yang sebenarnya hanya cara rumit untuk menyinkronkan hal-hal melalui variabel global - Tentu, Anda akhirnya akan melakukannya di dekat tenggat waktu, tetapi jangan merancang dengan itu sebagai tujuan Anda . Pada dasarnya, status dalam game bukan tumpukan, dan status dalam game tidak semuanya terkait.
GSM juga, seperti fungsi pointer dan perilaku non-lokal cenderung, membuat hal-hal debugging lebih sulit, meskipun debug semacam transisi negara besar itu tidak terlalu menyenangkan sebelum kita memilikinya juga. Set negara bukannya tumpukan negara tidak benar-benar membantu ini, tetapi Anda harus menyadarinya. Fungsi virtual daripada fungsi pointer dapat mengurangi itu.
sumber
Berikut ini contoh implementasi tumpukan gamestate yang menurut saya sangat berguna: http://creators.xna.com/en-US/samples/gamestatemanagement
Itu ditulis dalam C # dan untuk mengkompilasinya Anda memerlukan kerangka kerja XNA, namun Anda bisa melihat kode, dokumentasi dan video untuk mendapatkan ide.
Ini dapat mendukung transisi status, status transparan (seperti kotak pesan modal) dan status pemuatan (yang mengelola pembongkaran status yang ada dan memuat status berikutnya).
Saya menggunakan konsep yang sama dalam proyek hobi saya (non-C #) sekarang (memang, mungkin tidak cocok untuk proyek yang lebih besar) dan untuk proyek kecil / hobi saya pasti dapat merekomendasikan pendekatan ini.
sumber
Ini mirip dengan apa yang kami gunakan, setumpuk FSM. Pada dasarnya hanya memberi setiap negara fungsi masuk, keluar, dan centang dan memanggil mereka secara berurutan. Bekerja sangat baik untuk menangani hal-hal seperti memuat juga.
sumber
Salah satu volume "Permata Pemrograman Game" memiliki implementasi mesin negara di dalamnya yang dimaksudkan untuk status permainan; http://emergent.net/Global/Documents/textbook/Chapter1_GameAppFramework.pdf memiliki contoh cara menggunakannya untuk gim kecil, dan tidak boleh terlalu spesifik Gamebryo untuk dapat dibaca.
sumber
Hanya untuk menambahkan sedikit standardisasi ke dalam diskusi, istilah CS klasik untuk struktur data semacam ini adalah otomat pushdown .
sumber
Saya tidak yakin tumpukan sepenuhnya diperlukan serta membatasi fungsi sistem negara. Menggunakan tumpukan, Anda tidak dapat 'keluar' dari satu ke beberapa kemungkinan. Katakanlah Anda memulai di "Menu Utama" kemudian pergi ke "Load Game", Anda mungkin ingin pergi ke "Jeda" setelah berhasil memuat game yang disimpan dan kembali ke "Menu Utama" jika pengguna membatalkan beban.
Saya hanya akan meminta negara menentukan negara untuk diikuti ketika keluar.
Untuk kasus-kasus di mana Anda ingin kembali ke keadaan sebelum keadaan saat ini, misalnya "Menu Utama-> Pilihan-> Menu Utama" dan "Jeda-> Pilihan-> Jeda", cukup masukkan sebagai parameter startup ke status negara untuk kembali ke.
sumber
Solusi lain untuk transisi dan hal-hal lain seperti itu adalah menyediakan negara tujuan dan sumber, bersama dengan mesin negara, yang dapat dikaitkan dengan "mesin", apa pun itu. Yang benar adalah bahwa sebagian besar mesin negara mungkin perlu disesuaikan dengan proyek yang ada. Satu solusi mungkin menguntungkan game ini atau itu, solusi lain mungkin menghambatnya.
Status didorong dengan kondisi saat ini dan mesin sebagai parameter.
Negara muncul dengan cara yang sama. Apakah Anda memanggil
Enter()
yang lebih rendahState
adalah pertanyaan implementasi.Saat memasukkan, memperbarui atau keluar,
State
mendapatkan semua informasi yang dibutuhkan.sumber
Saya telah menggunakan sistem yang sangat mirip di beberapa permainan dan menemukan bahwa dengan beberapa pengecualian, ini berfungsi sebagai model UI yang sangat baik.
Satu-satunya masalah yang kami temui adalah kasus yang diinginkan dalam kasus tertentu untuk mengembalikan beberapa negara sebelum mendorong negara baru (kami mengubah ulang UI untuk menghapus persyaratan, karena biasanya itu merupakan tanda UI yang buruk) dan membuat gaya penyihir aliran linier (diselesaikan dengan mudah dengan meneruskan data ke negara berikutnya).
Implementasi yang kami gunakan sebenarnya membungkus stack dan menangani logika untuk memperbarui dan rendering, serta operasi pada stack. Setiap operasi di stack memicu peristiwa di negara bagian untuk memberi tahu mereka tentang operasi yang terjadi.
Beberapa fungsi pembantu ditambahkan juga untuk menyederhanakan tugas-tugas umum, seperti Swap (Pop & Push, untuk aliran linier) dan Reset (untuk kembali ke menu utama, atau mengakhiri aliran).
sumber
Ini adalah pendekatan yang saya ambil untuk hampir semua proyek saya, karena ia bekerja dengan sangat baik dan sangat sederhana.
Proyek terbaru saya, Sharplike , menangani aliran kontrol dengan cara yang tepat ini. Status kita semua terhubung dengan serangkaian fungsi acara yang dipanggil ketika status berubah, dan fitur konsep "bernama tumpukan" di mana Anda dapat memiliki banyak tumpukan negara dalam mesin negara yang sama dan bercabang di antaranya - sebuah konsep alat, dan tidak perlu, tetapi berguna untuk dimiliki.
Saya akan memperingatkan terhadap paradigma "beri tahu controller keadaan apa yang harus diikuti ketika ini berakhir" yang disarankan oleh Skizz: paradigma itu tidak terdengar secara struktural, dan itu membuat hal-hal seperti kotak dialog (yang dalam paradigma stack-state standar hanya melibatkan pembuatan baru sebutkan subclass dengan anggota baru, lalu bacalah saat Anda kembali ke status aktif) jauh lebih sulit daripada yang seharusnya.
sumber
Pada dasarnya saya menggunakan sistem yang tepat ini di beberapa sistem secara orthogonal; menu frontend dan dalam game (alias "jeda"), misalnya, memiliki tumpukan status mereka sendiri. UI dalam game juga menggunakan sesuatu seperti ini walaupun memiliki aspek "global" (seperti bilah kesehatan dan peta / radar) yang mungkin diganti oleh peralihan negara tetapi diperbarui secara umum di seluruh negara bagian.
Menu dalam gim mungkin "lebih baik" diwakili oleh DAG, tetapi dengan mesin keadaan implisit (setiap opsi menu yang menuju ke layar lain tahu cara menuju ke sana, dan menekan tombol kembali selalu muncul di bagian atas) efeknya adalah persis sama.
Beberapa dari sistem lain ini juga memiliki fungsionalitas "ganti keadaan teratas", tetapi itu biasanya diterapkan sebagai
StatePop()
diikuti olehStatePush(x);
.Penanganan kartu memori serupa karena saya benar-benar mendorong satu ton "operasi" ke dalam antrian operasi (yang secara fungsional melakukan hal yang sama dengan tumpukan, seperti halnya FIFO daripada LIFO); begitu Anda mulai menggunakan struktur semacam ini ("ada satu hal yang terjadi sekarang, dan ketika selesai muncul sendiri") ia mulai menginfeksi setiap area kode. Bahkan AI mulai menggunakan sesuatu seperti ini; AI "tidak mengerti" kemudian beralih ke "waspada" ketika pemain membuat suara tetapi tidak terlihat, dan akhirnya diangkat menjadi "aktif" ketika mereka melihat pemain (dan tidak seperti permainan yang lebih kecil saat itu, Anda tidak bisa menyembunyikan dalam kotak kardus dan buat musuh melupakanmu! Bukannya aku pahit ...).
GameState.h:
GameState.cpp:
sumber