Komunikasi Berbasis Acara dalam Mesin Game: Ya atau Tidak?

62

Saya membaca Game Coding Complete dan penulis merekomendasikan komunikasi Event Driven antara objek dan modul game.

Pada dasarnya, semua aktor permainan hidup harus berkomunikasi dengan modul utama (Fisika, AI, Logika Game, Tampilan Game, dll.) Melalui sistem pesan acara internal. Ini berarti harus merancang manajer acara yang efisien. Sistem yang dirancang buruk memakan siklus CPU, terutama yang memengaruhi platform seluler.

Apakah ini pendekatan yang terbukti dan direkomendasikan? Bagaimana saya harus memutuskan apakah akan menggunakannya?

Bunkai.Satori
sumber
Hai James, terima kasih atas jawaban Anda. Saya menyukainya, meskipun buku ini menggambarkan komunikasi Event Driven sebagai sistem yang sangat rumit yang tampaknya menghabiskan banyak sumber daya CPU secara signifikan.
Bunkai.Satori
Masukkan ke dalam jawaban dan tambahkan tautan ke ikhtisar tingkat tinggi dari sistem pesan acara yang saya berikan sebagai jawaban di stack overflow. Nikmati! Ingat saja bahwa apa yang dianggap kompleks oleh sebagian orang tidak harus :)
James
Anda dapat memeriksa jawaban ini dengan baik menggunakan c ++ 11: stackoverflow.com/a/22703242/2929762
user2826084
libuvbaru-baru ini muncul sebagai perpustakaan acara yang sukses. (Ada di C. Node.js adalah kasus penggunaannya yang paling terkenal.)
Anko

Jawaban:

46

Ini adalah perluasan dari komentar saya menjadi jawaban penuh, seperti yang disarankan.

Ya , sederhana dan sederhana. Komunikasi perlu terjadi dan sementara ada situasi di mana 'Apakah kita sudah sampai?' -jenis polling diperlukan, memeriksa hal-hal untuk melihat apakah mereka harus melakukan sesuatu yang lain umumnya membuang-buang waktu. Alih-alih, Anda bisa membuat mereka bereaksi terhadap hal-hal yang diperintahkan kepada mereka untuk dilakukan. Plus, jalur komunikasi yang didefinisikan dengan baik antara objek / sistem / modul meningkatkan pengaturan paralel secara signifikan.

Saya telah memberikan tinjauan tingkat tinggi tentang sistem pengiriman pesan acara di Stack Overflow . Saya telah menggunakannya dari sekolah menjadi judul-judul game profesional dan sekarang produk-produk non-game, disesuaikan dengan kasus penggunaan setiap saat tentu saja.

EDIT : Untuk menjawab pertanyaan komentar tentang bagaimana Anda tahu objek mana yang harus menerima pesan : Objek itu sendiri harus Requestdiberitahu tentang peristiwa. Anda EventMessagingSystem(EMS) akan membutuhkan Register(int iEventId, IEventMessagingSystem * pOjbect, (EMSCallback)fpMethodToUseForACallback)serta pencocokan Unregister(membuat entri yang unik untuk iEventIdkeluar dari pointer objek dan callback). Dengan cara ini, ketika suatu objek ingin tahu tentang suatu pesan, ia dapat Register()menggunakan sistem. Ketika itu tidak perlu lagi tahu tentang peristiwa itu, itu bisaUnregister(). Jelas, Anda ingin kumpulan objek pendaftaran panggilan balik ini dan cara yang efektif untuk menambah / menghapusnya dari daftar. (Saya biasanya menggunakan array pemesanan sendiri; cara yang bagus untuk mengatakan mereka melacak alokasi mereka sendiri antara kumpulan kumpulan objek yang tidak digunakan dan array yang menggeser ukurannya di tempat ketika diperlukan).

EDIT : Untuk game yang sepenuhnya berfungsi dengan loop pembaruan dan sistem pesan acara, Anda mungkin ingin memeriksa proyek sekolah lama saya . Posting Stack Overflow yang ditautkan di atas juga merujuk padanya.

James
sumber
Halo James, karena saya berpikir tentang sistem perpesanan acara internal lebih banyak, saya pikir itu tidak perlu menambahkan biaya lebih ke mesin. Misalnya, jika ada 50 objek di layar, tetapi hanya 5 dari mereka yang seharusnya mengubah perilaku mereka; di bawah sistem tradisional, semua 50 pelaku perlu memeriksa semua kemungkinan tindakan mereka, untuk melihat apakah mereka harus melakukan sesuatu. Namun, dengan penggunaan pesan acara, hanya 5 pesan yang akan dikirim ke 5 tujuan tersebut dengan perubahan tindakan tertentu. Itu terlihat seperti pendekatan penghematan waktu.
Bunkai.Satori
Cara sistem yang ditautkan dalam jawaban saya di atas bekerja adalah bahwa objek hanya mendaftar untuk mendengar tentang pesan yang mereka inginkan .. Kami akan menggunakan ini untuk keuntungan kami dalam permainan video di mana mungkin ada 100-200 objek di tingkat, tetapi Anda hanya 'aktifkan' yang pemain dapat berinteraksi secara langsung, menjaga jumlah hal yang didengarkan sekitar 10 atau lebih. Semua dalam semua jenis sistem ini harus 'lebih pintar' daripada 'apakah kita sudah sampai?' sistem pemungutan suara, dan harus mengurangi overhead mesin, setidaknya sejauh menyangkut komunikasi.
James
Ada satu hal yang berkaitan dengan sistem yang digerakkan oleh peristiwa yang membingungkan saya: Di bawah sistem tradisional di mana setiap objek memiliki kumpulan metode yang telah ditentukan (OnUpdate (), OnMove (), OnAI (), OnCollisionCheck () ...) secara teratur dipanggil, setiap objek adalah bertanggung jawab untuk memeriksa dan mengelola negaranya. Di bawah sistem yang digerakkan oleh peristiwa, harus ada beberapa kondisi sistem master yang memeriksa setiap objek, dan kemudian mengirim pesan kepada mereka di mana beberapa peristiwa terdeteksi. Bagi saya, ini menstandarisasi status objek yang mungkin, dan membatasi kebebasan untuk membuat perilaku objek yang unik. Benarkah itu?
Bunkai.Satori
Pola Observer adalah alternatif khas untuk polling. en.wikipedia.org/wiki/Observer_pattern
Ricket
1
@ hamlin11 Senang informasi ini masih membantu orang :) Mengenai pendaftaran, jika hal ini terjadi sedikit, ingat Anda akan ingin mengoptimalkannya untuk kecepatan, memiliki kumpulan objek pendaftaran untuk menarik dari, dll
James
22

Pendapat saya adalah Anda harus mulai membuat game dan menerapkan apa yang Anda sukai. Ketika Anda melakukan itu, Anda akan menemukan diri Anda menggunakan MVC di beberapa tempat, tetapi tidak di tempat lain; Peristiwa beberapa tempat, tetapi tidak yang lain; komponen beberapa tempat, tetapi warisan lainnya; desain bersih beberapa tempat, dan desain crufty lainnya.

Dan itu tidak masalah, karena ketika Anda selesai Anda akan benar-benar memiliki permainan, dan permainan itu jauh lebih keren daripada sistem penyampaian pesan.

pengguna744
sumber
2
Hai Joe, terima kasih atas jawaban Anda, saya menyukainya. Anda percaya, bahwa tidak perlu mendorong pendekatan apa pun secara artifisial. Saya harus mendesain aplikasi karena saya pikir akan berhasil, dan jika sesuatu tidak berfungsi kemudian, saya hanya akan mengulanginya.
Bunkai.Satori
Inilah mengapa sistem ada. Banyak orang telah melakukan apa yang Anda katakan, menyaksikan mimpi buruk, dan mengatakan harus ada cara yang lebih baik. Anda bisa mengulang kesalahan mereka atau belajar darinya dan mungkin lebih maju.
user441521
16

Pertanyaan yang lebih baik adalah, alternatif apa yang ada? Dalam sistem yang sedemikian kompleks dengan modul yang dibagi dengan baik untuk fisika, AI, dll., Bagaimana lagi Anda dapat mengatur sistem ini?

Pesan lewat tampaknya menjadi solusi "terbaik" untuk masalah ini. Saya tidak bisa memikirkan alternatif sekarang. Tetapi ada banyak contoh pesan yang lewat dalam praktek. Bahkan, sistem operasi menggunakan passing pesan untuk beberapa fungsinya. Dari Wikipedia :

Pesan juga biasanya digunakan dalam arti yang sama sebagai sarana komunikasi antarproses; teknik umum lainnya adalah stream atau pipa, di mana data dikirim sebagai urutan item data dasar sebagai gantinya (versi tingkat lebih tinggi dari sirkuit virtual).

(Komunikasi antarproses adalah komunikasi antar proses (mis. Menjalankan instance program) dalam lingkungan sistem operasi)

Jadi, jika itu cukup baik untuk sistem operasi, itu mungkin cukup baik untuk sebuah game, bukan? Ada manfaat lain juga, tapi saya akan membiarkan artikel Wikipedia tentang pesan yang lewat melakukan penjelasan.

Saya juga mengajukan pertanyaan tentang Stack Overflow, "Struktur data untuk pengiriman pesan dalam suatu program?" , yang mungkin ingin Anda baca.

Ricket
sumber
Hai Ricket, terima kasih atas jawaban Anda. Anda bertanya apa cara lain yang bisa digunakan untuk membiarkan objek permainan saling berkomunikasi. Apa yang terlintas dalam pikiran saya adalah metode panggilan langsung. Benar, itu tidak memberi Anda begitu banyak fleksibilitas, tetapi di sisi lain, itu menghindari pembuatan pesan acara, lewat, membaca, dll. Kami masih berbicara tentang platform mobile, bukan tentang game high-end. Sistem operasi havily menggunakan sistem pesan internal. Namun, itu tidak dirancang untuk berjalan secara real-time, di mana bahkan penundaan kecil menyebabkan gangguan.
Bunkai.Satori
Biarkan saya membuka pertanyaan ini untuk sementara waktu. Saya ingin mengumpulkan lebih banyak pendapat, sebelum menutupnya.
Bunkai.Satori
Panggilan metode langsung umumnya menghasilkan penggabungan kelas-kelas yang saling memanggil. Ini tidak baik untuk sistem yang dipisahkan menjadi komponen yang seharusnya dapat dipertukarkan. Ada beberapa pola yang dapat memfasilitasi pemanggilan metode langsung dengan sedikit kohesi (mis. Bagian "controller" dari MVC pada dasarnya melayani tujuan ini untuk memfasilitasi permintaan tampilan model, kecuali jika Anda memasangkannya) tetapi secara umum, pengiriman pesan adalah satu-satunya cara untuk sebuah sistem untuk memiliki nol kopling antar subsistem (atau setidaknya satu-satunya cara saya tahu).
Ricket
Ah, jadi sekarang kita mulai membahas pola. Saya telah mendengar sedikit tentang pendekatan pemrograman ini. Sekarang, saya mulai memahami pola apa itu. Ini sangat berbeda dengan desain aplikasi. Anda masivelly mengontrol objek, sambil menggunakan kode yang sama untuk memeriksa setiap objek. Setelah memeriksa objek Anda mengatur atributnya sesuai.
Bunkai.Satori
1
Pertanyaan "Struktur Data ..." memiliki jawaban yang LUAR BIASA. Saya akan mengatakan, jawaban yang Anda pilih dan artikel Nebula3 yang menyertainya adalah deskripsi terbaik dari arsitektur mesin permainan dari ukurannya yang pernah saya lihat.
deft_code
15

Pesan umumnya bekerja dengan baik ketika:

  1. Hal yang mengirim pesan tidak peduli jika diterima.
  2. Pengirim tidak perlu mendapatkan balasan segera dari penerima.
  3. Mungkin ada beberapa penerima mendengarkan satu pengirim.
  4. Pesan akan dikirim jarang atau tidak dapat diprediksi. (Dengan kata lain, jika setiap objek perlu mendapatkan pesan "perbarui" setiap frame, pesan tidak terlalu banyak membuahkan hasil.)

Semakin banyak kebutuhan Anda cocok dengan daftar itu, semakin baik pesan yang cocok. Pada tingkat yang sangat umum, mereka cukup bagus. Mereka melakukan pekerjaan yang baik dengan tidak membuang-buang siklus CPU hanya untuk tidak melakukan apa pun seperti polling atau solusi global lainnya. Mereka fantastis dalam memisahkan bagian-bagian dari basis kode, yang selalu membantu.

banyak sekali
sumber
4

Sejauh ini jawaban yang bagus dari James dan Ricket, saya hanya menjawab untuk menambahkan catatan hati-hati. Komunikasi lewat pesan / event-driven tentu merupakan alat penting dalam gudang pengembang, tetapi dapat dengan mudah digunakan secara berlebihan. Ketika Anda memiliki palu, semuanya terlihat seperti paku, dan sebagainya.

Anda benar-benar, 100%, harus berpikir tentang aliran data di sekitar judul Anda, dan sepenuhnya menyadari bagaimana informasi dilewatkan dari satu subsistem ke yang lain. Dalam beberapa kasus, menyampaikan pesan jelas merupakan yang terbaik; pada yang lain, mungkin lebih tepat untuk satu subsistem untuk beroperasi di atas daftar objek yang dibagikan, memungkinkan subsistem lain untuk juga beroperasi pada daftar bersama yang sama; dan masih banyak lagi metode lainnya.

Setiap saat Anda harus mengetahui subsistem mana yang memerlukan akses ke data mana, dan kapan mereka perlu mengaksesnya. Ini memengaruhi kemampuan Anda untuk memparalelkan dan mengoptimalkan, serta membantu Anda menghindari masalah yang lebih berbahaya ketika berbagai bagian mesin Anda menjadi terlalu dekat. Anda harus berpikir tentang meminimalkan penyalinan yang tidak perlu di sekitar data, dan bagaimana tata letak data Anda memengaruhi penggunaan cache Anda. Semuanya akan memandu Anda ke solusi terbaik dalam setiap kasus.

Karena itu, hampir setiap game yang pernah saya garap memiliki sistem pemberitahuan pesan / event event asynchronous yang solid. Ini memungkinkan Anda untuk menulis kode yang ringkas, efisien dan dapat dipelihara, bahkan dalam menghadapi kebutuhan desain yang kompleks dan cepat berubah.

MrCranky
sumber
+1 untuk info tambahan yang bagus. Hai, MrCranky, Terima kasih. Menurut apa yang Anda katakan, sebaiknya mempertimbangkan sistem Event Messaging bahkan untuk game mobile. Namun, perencanaan tidak boleh diabaikan, dan itu harus dipertimbangkan dengan sangat baik di mana sistem pesan akan digunakan.
Bunkai.Satori
4

Yah, saya tahu bahwa posting ini cukup lama, tetapi saya tidak bisa menolak.

Saya baru-baru ini membangun mesin game. Ini menggunakan perpustakaan pesta 3d untuk rendering dan fisika, tapi saya menulis bagian inti, yang mendefinisikan dan memproses entitas dan logika permainan.

Mesinnya pasti mengikuti pendekatan tradisional. Ada loop pembaruan utama yang memanggil fungsi pembaruan untuk semua entitas. Tabrakan secara langsung dilaporkan melalui panggilan balik pada entitas. Komunikasi antar entitas dibuat menggunakan smart pointer yang dipertukarkan antar entitas.

Ada sistem pesan primitif, Yang memproses hanya sekelompok kecil entitas untuk mesin pesan. Pesan-pesan itu lebih disukai diproses pada akhir interaksi game (contohnya adalah pembuatan entitas atau penghancuran) karena mereka dapat mengacaukan dengan daftar pembaruan. Jadi, di akhir setiap loop game, daftar kecil pesan dikonsumsi.

Meskipun sistem pesan primitif, saya akan mengatakan bahwa sistem ini sebagian besar "pembaruan berbasis loop".

Baik. Setelah menggunakan sistem ini, saya pikir itu sangat sederhana, cepat dan terorganisir dengan baik. Logika permainan terlihat dan mandiri di dalam entitas, tidak dinamis seperti pesan quewe. Saya benar-benar tidak ingin menjadikannya event driven karena menurut saya sistem acara memperkenalkan kompleksitas yang tidak perlu pada logika game, dan membuat kode game sangat sulit untuk dipahami dan didebug.

Tapi, saya juga berpikir bahwa sistem "update loop based" murni seperti milik saya punya beberapa masalah juga.

Misalnya, Dalam beberapa saat, satu entitas mungkin berada pada "keadaan tidak melakukan apa-apa", mungkin sedang menunggu pemain mendekat atau yang lainnya. Dalam sebagian besar kasus, entitas membakar waktu prosesor dengan sia-sia dan lebih baik mematikan entitas, dan menyalakannya saat peristiwa tertentu terjadi.

Jadi, di mesin gim berikutnya, saya akan mengadopsi pendekatan yang berbeda. Entitas akan mendaftarkan diri untuk operasi mesin, seperti pembaruan, gambar, deteksi tabrakan dan sebagainya. Setiap peristiwa ini akan memiliki daftar antarmuka entitas yang terpisah untuk entitas yang sebenarnya.

Artur Correa
sumber
Anda akan menemukan bahwa entitas menjadi basis kode monster yang menjadi sulit dikelola dengan segala jenis kompleksitas dalam permainan. Anda akhirnya akan menyatukan mereka dan itu akan payah untuk menambah atau mengubah fitur. Dengan memecah fitur Anda menjadi komponen-komponen kecil, akan lebih mudah untuk memelihara dan menambahkan fitur. Lalu pertanyaannya menjadi bagaimana komponen ini berkomunikasi? Jawabannya adalah peristiwa dari satu komponen yang meningkatkan fungsi komponen lainnya sambil meneruskan data primitif dalam argumen.
user441521
3

Iya. Ini adalah cara yang sangat efisien bagi sistem permainan untuk berkomunikasi satu sama lain. Acara membantu Anda memisahkan banyak sistem dan memungkinkan untuk menyusun berbagai hal secara terpisah tanpa mengetahui keberadaan satu sama lain. Ini berarti kelas Anda dapat lebih mudah di-prototipe dan waktu kompilasi lebih cepat. Lebih penting lagi, Anda berakhir dengan desain kode datar alih-alih kekacauan ketergantungan.

Manfaat besar lainnya dari acara adalah bahwa mereka mudah dialirkan melalui jaringan atau saluran teks lainnya. Anda dapat merekamnya untuk pemutaran nanti. Kemungkinannya tidak terbatas.

Manfaat lain: Anda dapat meminta beberapa subsistem mendengarkan acara yang sama. Misalnya, semua tampilan jauh Anda (pemain) dapat secara otomatis berlangganan ke acara pembuatan entitas dan menelurkan entitas pada setiap klien dengan sedikit pekerjaan di pihak Anda. Bayangkan berapa banyak pekerjaan yang akan terjadi jika Anda tidak menggunakan acara: Anda harus melakukan Update()panggilan di suatu tempat atau mungkin menelepon view->CreateEntitydari logika Game (di mana pengetahuan tentang tampilan dan informasi apa yang diperlukan tidak termasuk). Sulit untuk menyelesaikan masalah itu tanpa kejadian.

Dengan acara Anda mendapatkan solusi yang elegan dan terpisah yang mendukung jumlah objek tak terbatas dari jenis tak terbatas yang semuanya dapat dengan mudah berlangganan acara dan melakukan hal mereka ketika sesuatu terjadi dalam permainan Anda. Itu sebabnya acara sangat bagus.

Lebih detail dan implementasinya di sini .

pengguna2826084
sumber
Poin bagus, meski sepihak. Saya selalu curiga pada umumnya: Apakah ada anti -kasus penggunaan untuk acara?
Anko
1
Poin anti-penggunaan: ketika Anda benar-benar harus memiliki respons langsung. Ketika apa pun yang Anda ingin lakukan pada suatu peristiwa selalu dieksekusi secara langsung dan di utas yang sama. Ketika sama sekali tidak ada penundaan luar yang dapat menunda penyelesaian panggilan. Ketika Anda hanya memiliki dependensi linear. Ketika Anda jarang melakukan banyak hal secara bersamaan. Jika Anda melihat node.js, semua panggilan io didasarkan pada peristiwa. Node.js adalah satu tempat di mana acara telah dilaksanakan 100% dengan benar.
user2826084
Sistem acara tidak harus async. Anda dapat menggunakan coroutine untuk mensimulasikan async, sambil mendapatkan sinkronisasi saat Anda membutuhkannya.
user441521
2

Dari apa yang saya lihat, sepertinya tidak terlalu umum untuk memiliki mesin yang sepenuhnya berdasarkan pesan. Tentu saja, ada subsistem yang cocok untuk sistem pesan seperti itu, seperti jaringan, GUI, dan mungkin yang lainnya. Namun secara umum, ada beberapa masalah yang dapat saya pikirkan:

  • Mesin game menangani data dalam jumlah besar.
  • Game harus cepat (20-30 FPS harus menjadi minimum).
  • Seringkali perlu untuk mengetahui apakah sesuatu telah dilakukan atau kapan akan dilakukan.

Dengan pendekatan pengembang game umum "itu harus seefisien mungkin" sistem pesan seperti itu tidak begitu umum.

Namun, saya setuju bahwa Anda harus melanjutkan dan mencobanya. Tentu ada banyak keuntungan dengan sistem seperti itu dan daya komputasi tersedia dengan murah saat ini.

mrbinary
sumber
Saya tidak tahu apakah saya setuju dengan ini. Alternatifnya adalah polling yang boros. Hanya menanggapi acara adalah yang paling efisien. Ya, masih akan ada beberapa jajak pendapat yang akan terjadi dan memunculkan acara tetapi ada sejumlah hal yang juga berorientasi pada acara.
user441521
Saya juga tidak setuju dengan ini. Jumlah mesin permainan data yang ditangani sebagian besar tidak relevan, karena pesan acara dirancang untuk komunikasi subsistem-subsistem. Objek game tidak boleh berkomunikasi dengan objek game lain secara langsung (meskipun penangan peristiwa khusus dalam objek bisa menjadi pengecualian). Karena jumlah subsistem yang relatif kecil ini, dan area "minat" mereka, biaya kinerja dari tulang punggung perpesanan yang dirancang dengan baik, dalam mesin multi-ulir dapat diabaikan.
Ian Young