Saya telah mengerjakan beberapa proyek hobi 3-4 tahun terakhir. Game 2d dan 3d sederhana. Tapi belakangan ini saya sudah memulai proyek yang lebih besar. Soo dalam beberapa bulan terakhir saya sudah mencoba merancang kelas objek game yang bisa menjadi basis dari semua objek game saya. Jadi setelah banyak mencoba & mati pengujian saya beralih ke Google yang dengan cepat menunjuk saya ke beberapa GDC PDF dan PowerPoint. Dan sekarang saya mencoba untuk memahami objek permainan berbasis komponen.
Saya mengerti bahwa mesin menciptakan objek permainan dan kemudian menempel berbagai komponen yang menangani hal-hal seperti kesehatan, fisika, jaringan, dan apa pun yang Anda lakukan. Tapi yang tidak saya mengerti adalah bagaimana komponen X tahu jika Y telah mengubah keadaan objek. Seperti bagaimana PhysicsComponent tahu jika pemain masih hidup, karena kesehatan dikendalikan oleh HealthComponent ..? Dan bagaimana HealthComponent memainkan "pemain-mati-animasi"?
Saya mendapat kesan bahwa itu adalah sesuatu seperti ini (Dalam HealthComponent):
if(Health < 0) {
AnimationComponent.PlayAnimation("played-died-animation")
}
Tapi sekali lagi, bagaimana HealthComponent tahu bahwa objek game itu dilampirkan untuk memiliki AnimationComponent? Satu-satunya solusi yang saya lihat di sini adalah
Cek untuk melihat apakah AnimationComponent terpasang atau tidak (baik di dalam kode komponen atau di sisi mesin)
Memiliki komponen memerlukan komponen lain, tetapi itu tampaknya memperjuangkan seluruh desain komponen.
Tulis seperti, HealthWithAnimationComponent, HealthNoAnimationComponent, dan seterusnya, yang sekali lagi tampaknya memperjuangkan seluruh ide desain komponen.
Jawaban:
Dalam semua contoh Anda, ada masalah yang mengerikan. Komponen kesehatan perlu tahu tentang setiap jenis komponen yang mungkin perlu merespons kematian entitas. Karena itu, tidak ada skenario Anda yang sesuai. Entitas Anda memiliki komponen kesehatan. Ini memiliki komponen animasi. Tidak bergantung atau tahu tentang yang lain. Mereka berkomunikasi melalui sistem pesan.
Ketika komponen kesehatan mendeteksi bahwa entitas telah 'mati', ia mengirimkan pesan 'Aku mati'. Merupakan tanggung jawab komponen animasi untuk merespons pesan ini dengan memainkan animasi yang sesuai.
Komponen kesehatan tidak mengirim pesan langsung ke komponen animasi. Mungkin itu menyiarkannya ke setiap komponen dalam entitas itu, mungkin ke seluruh sistem; mungkin komponen animasi perlu memberi tahu sistem pesan bahwa itu tertarik pada pesan 'saya mati'. Ada banyak cara untuk menerapkan sistem pesan. Bagaimanapun Anda menerapkannya, intinya adalah bahwa komponen kesehatan dan komponen animasi tidak pernah perlu tahu atau peduli jika yang lain ada, dan menambahkan komponen baru tidak akan pernah perlu memodifikasi komponen yang sudah ada untuk mengirimkan pesan yang sesuai kepada mereka.
sumber
Cara Artemis memecahkan masalah adalah dengan tidak melakukan pemrosesan dalam Komponen. Komponen hanya berisi data yang mereka butuhkan. Sistem membaca beberapa jenis komponen dan melakukan pemrosesan apa pun yang diperlukan.
Jadi, dalam kasus Anda, Anda mungkin memiliki RenderSystem yang membaca di HealthComponent (dan lainnya) dan memainkan antrian hingga animasi yang sesuai. Memisahkan data dari fungsi dengan cara ini membuatnya lebih mudah untuk menjaga dependensi dikelola dengan baik.
sumber
Dalam kode Anda, Anda bisa ada cara (saya menggunakannya, mungkin beberapa cara lain ada) untuk mengetahui apakah objek berubah keadaan:
Untuk ini saya gunakan, 1. Fungsi HasComponent dari GameObject, atau 2. ketika Anda melampirkan komponen Anda dapat memeriksa dependensi dalam beberapa fungsi membangun, atau 3. Jika saya tahu pasti bahwa objek memiliki komponen ini, saya hanya menggunakannya.
Dalam beberapa artikel yang pernah saya baca, bahwa dalam komponen sistem Ideal tidak saling bergantung, tetapi dalam kehidupan nyata tidak demikian.
Adalah ide yang buruk untuk menulis komponen seperti itu. Di aplikasi saya, saya membuat komponen Kesehatan paling independen. Sekarang saya sedang memikirkan beberapa pola Observer yang memberi tahu pelanggan tentang beberapa peristiwa tertentu (misalnya "hit", "heal" dll). Jadi AnimationComponent harus memutuskan sendiri kapan harus memutar animasi.
Tetapi ketika saya telah membaca artikel tentang CBES, saya terkesan, jadi saya sangat senang sekarang ketika saya menggunakan CBES dan menemukan kemungkinan-kemungkinan baru untuk itu.
sumber
Seperti Michael, kata Patrick Hughes dan Blecki. Solusi untuk menghindari hanya memindahkan masalah di sekitar adalah dengan meninggalkan ideologi yang menyebabkan masalah di tempat pertama.
Ini kurang OOD dan lebih seperti Pemrograman Fungsional. Ketika saya mulai bereksperimen dengan Desain Berbasis Komponen, saya melihat masalah ini di ujung jalan. Saya mencari lebih banyak di Google, dan saya menemukan "Pemrograman Fungsional Reaktif" sebagai solusi.
Sekarang komponen saya hanyalah kumpulan variabel dan bidang yang menggambarkan kondisi saat ini. Kemudian saya memiliki banyak kelas "Sistem" yang memperbarui semua komponen yang relevan dengan mereka. Bagian reaktif dicapai dengan menjalankan Sistem dalam urutan yang jelas. Ini memastikan bahwa Sistem apa pun yang berada di baris berikutnya untuk melakukan pemrosesan dan pembaruannya, dan komponen dan entitas apa pun yang ingin dibaca dan diperbarui, selalu bekerja dengan data terbaru.
Namun, dengan cara tertentu Anda masih dapat mengklaim bahwa masalahnya telah bergerak lagi. Karena bagaimana jika tidak mudah untuk memesan Sistem mana yang perlu Anda jalankan? Bagaimana jika ada hubungan siklus dan hanya masalah waktu sebelum Anda menatap kekacauan jika-ada dan beralih pernyataan? Ini bentuk pesan implisit, bukan? Sekilas, saya pikir itu risiko kecil. Biasanya, semuanya diproses secara berurutan. Sesuatu seperti: Input Pemain -> Posisi Entitas -> Deteksi Tabrakan -> Logika Game -> Rendering -> Mulai dari awal. Dalam hal ini, Anda akan memiliki satu Sistem untuk masing-masing, berikan setiap Sistem dengan metode pembaruan (), dan kemudian jalankan secara berurutan di gameloop Anda.
sumber