"The Game Object" - dan desain berbasis komponen

25

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

  1. Cek untuk melihat apakah AnimationComponent terpasang atau tidak (baik di dalam kode komponen atau di sisi mesin)

  2. Memiliki komponen memerlukan komponen lain, tetapi itu tampaknya memperjuangkan seluruh desain komponen.

  3. Tulis seperti, HealthWithAnimationComponent, HealthNoAnimationComponent, dan seterusnya, yang sekali lagi tampaknya memperjuangkan seluruh ide desain komponen.

Hayer
sumber
1
Sukai pertanyaan itu. Seharusnya saya bertanya pada bulan yang sama, tetapi tidak pernah melakukannya. Masalah tambahan yang saya hadapi adalah ketika objek game memiliki banyak instance dari komponen yang sama (beberapa animasi misalnya). Akan lebih bagus jika jawabannya bisa menyentuh itu. Saya akhirnya menggunakan pesan untuk pemberitahuan, dengan variabel dibagi di antara semua komponen objek Game (jadi mereka tidak perlu mengirim pesan untuk mendapatkan nilai untuk variabel).
ADB
1
Tergantung pada jenis gim, Anda mungkin tidak akan memiliki objek gim yang memiliki komponen kesehatan dan tidak ada komponen animasi. Dan semua gameobjects ini mungkin representasi dari sesuatu seperti Unit. Jadi Anda dapat membuang komponen kesehatan, dan membuat UnitComponent yang akan memiliki kesehatan lapangan, dan tahu tentang semua komponen unit yang perlu. Granularitas komponen ini tidak benar-benar membantu apa pun - lebih realistis untuk memiliki satu komponen per domain (rendering, audio, fisika, logika permainan).
Kikaimaru

Jawaban:

11

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.

Blecki
sumber
Oke, ini masuk akal. Tetapi siapa yang menyatakan "status" seperti 'mati', atau 'portal-rusak', dll. Komponen atau mesin? Karena menambahkan status 'mati' ke sesuatu yang tidak akan pernah memiliki komponen kesehatan terlampir sepertinya agak sia-sia bagi saya. Saya kira saya hanya akan menyelam dan mulai menguji beberapa kode dan melihat apa yang berhasil.
hayer
Michael dan Patrick Hughes memiliki jawaban yang tepat di atas. Komponen hanyalah data; jadi itu bukan komponen kesehatan yang mendeteksi ketika entitas telah mati dan mengirim pesan, itu adalah bagian yang lebih tinggi dari logika khusus game. Bagaimana abstrak itu terserah Anda. Keadaan kematian yang sebenarnya tidak perlu disimpan di mana pun. Objek mati jika kesehatannya <0, dan komponen kesehatan dapat merangkum sedikit logika pengecekan data tanpa melanggar 'tidak ada perilaku! pembatasan jika Anda hanya mempertimbangkan hal-hal yang mengubah status komponen sebagai perilaku.
Blecki
Hanya ingin tahu, bagaimana Anda menangani Componenent Movement? Ketika mendeteksi input, ia perlu meningkatkan kecepatan di PositionComponent. Seperti apa pesannya?
Tips48
8

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.

Michael
sumber
Ini akhirnya menjadi cara yang bagus untuk menangani masalah: Komponen mewakili properti sementara Sistem mengikat bersama properti yang berbeda dan menggunakannya untuk melakukan pekerjaan. Ini adalah perubahan besar dari pemikiran OOP tradisional dan membuat kepala sebagian orang sakit =)
Patrick Hughes
Okey, sekarang saya benar-benar tersesat .. "Sebaliknya, dalam ES, jika Anda memiliki 100 unit di medan perang, masing-masing diwakili oleh Entitas, maka Anda memiliki nol salinan dari masing-masing metode yang dapat dipanggil pada unit - karena Entitas tidak mengandung metode. Komponen juga tidak mengandung metode. Sebaliknya, Anda memiliki sistem eksternal untuk setiap aspek, dan sistem eksternal itu berisi semua metode yang dapat dipanggil pada Entitas apa pun yang memiliki Komponen yang menandainya kompatibel dengan ini. sistem." Nah, di mana data dalam GunComponent disimpan? Seperti putaran, dll. Jika semua entitas berbagi komponen yang sama.
hayer
1
Sejauh yang saya mengerti, semua entitas tidak memiliki komponen yang sama, masing-masing entitas dapat memiliki instance komponen N yang menyertainya. Sistem kemudian meminta permainan untuk daftar semua entitas yang memiliki instance komponen yang mereka pedulikan terlampir padanya dan kemudian melakukan pemrosesan apa pun pada mereka
Jake Woods
Ini hanya memindahkan masalah. Bagaimana sistem mengetahui komponen mana yang akan digunakan? Suatu sistem dapat membutuhkan sistem lain juga (sistem StateMachine mungkin ingin memanggil animasi misalnya). Namun, itu memecahkan masalah WHO yang memiliki data. Faktanya, implementasi yang lebih sederhana adalah memiliki kamus di objek game dan setiap sistem membuat variabel-variabelnya di sana.
ADB
Itu memang memindahkan masalah tetapi ke tempat yang lebih bisa dipertahankan. Sistem memiliki komponen yang relevan dengan kabel. Sistem dapat berkomunikasi satu sama lain melalui Komponen (StateMachine dapat menetapkan nilai komponen yang dibaca Animasi untuk mengetahui apa yang harus dilakukan (atau bisa memadamkan Peristiwa). Pendekatan kamus terdengar seperti Pola Properti yang juga dapat berfungsi. Hal yang menyenangkan tentang Komponen adalah bahwa properti terkait dikelompokkan bersama dan mereka dapat diperiksa secara statis. Tidak ada kesalahan aneh karena Anda menambahkan "Dammage" di satu tempat tetapi mencoba untuk mengambilnya menggunakan "Damage" di tempat lain
Michael
6

Dalam kode Anda, Anda bisa ada cara (saya menggunakannya, mungkin beberapa cara lain ada) untuk mengetahui apakah objek berubah keadaan:

  1. Mengirim pesan.
  2. Baca langsung data dari komponen.

1) Periksa apakah ada komponen AnimationComponent atau tidak (baik di dalam kode komponen atau di sisi mesin)

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.

2) Memiliki komponen memerlukan komponen lain, tetapi itu tampaknya memperjuangkan seluruh desain komponen.

Dalam beberapa artikel yang pernah saya baca, bahwa dalam komponen sistem Ideal tidak saling bergantung, tetapi dalam kehidupan nyata tidak demikian.

3) Tulis seperti, HealthWithAnimationComponent, HealthNoAnimationComponent, dan seterusnya, yang sekali lagi tampaknya memperjuangkan seluruh ide desain komponen.

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.

Yevhen
sumber
1
Nah, google.no/… @ slide 16
hayer
@obobenko, tolong berikan tautan ke artikel tentang CBES. Saya juga sangat menarik di dalamnya;)
Edward83
1
Dan lambdor.net/?p=171 @ bawah, ini merupakan ringkasan pertanyaan saya. Bagaimana fungsi yang berbeda dapat didefinisikan dalam hal komponen yang relatif kompleks dan non-elementer? Apa komponen paling dasar? Dengan cara apa komponen dasar berbeda dari fungsi murni? Bagaimana komponen yang ada dapat berkomunikasi secara otomatis dengan pesan baru dari komponen baru? Apa gunanya mengabaikan pesan yang tidak diketahui komponen? Apa yang terjadi dengan model input-proses-output?
hayer
1
di sini adalah jawaban yang baik pada CBES stackoverflow.com/a/3495647/903195 sebagian besar artikel yang saya teliti berasal dari jawaban ini. Saya mulai dan terinspirasi dengan cowboyprogramming.com/2007/01/05/evolve-your-heirachy lalu Di Permata 5 (seingat saya) ada artikel bagus dengan contoh.
Yevhen
Tetapi bagaimana dengan konsep pemrograman fungsional-reaktif lain, bagi saya pertanyaan ini masih terbuka, tetapi mungkin bagi Anda adalah arah yang baik untuk penelitian.
Yevhen
3

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.

uhmdown
sumber