Saya mencoba untuk mendapatkan kepala saya di sekitar desain entitas berbasis komponen.
Langkah pertama saya adalah membuat berbagai komponen yang bisa ditambahkan ke objek. Untuk setiap jenis komponen saya memiliki manajer, yang akan memanggil fungsi pembaruan setiap komponen, melewati hal-hal seperti keadaan keyboard dll sesuai kebutuhan.
Hal berikutnya yang saya lakukan adalah menghapus objek, dan hanya memiliki setiap komponen dengan ID. Jadi suatu objek didefinisikan oleh komponen yang memiliki Id yang sama.
Sekarang, saya berpikir bahwa saya tidak memerlukan manajer untuk semua komponen saya, misalnya saya punya SizeComponent
, yang hanya memiliki Size
properti). Akibatnya SizeComponent
tidak ada metode pembaruan, dan metode pembaruan manajer tidak melakukan apa pun.
Pikiran pertama saya adalah memiliki ObjectProperty
kelas yang dapat ditanyakan oleh komponen, alih-alih menjadikannya sebagai properti komponen. Jadi suatu objek akan memiliki sejumlah ObjectProperty
dan ObjectComponent
. Komponen akan memiliki logika pembaruan yang menanyakan objek untuk properti. Manajer akan mengelola memanggil metode pembaruan komponen.
Ini kelihatannya seperti over-engineering bagi saya, tetapi saya tidak berpikir saya bisa menyingkirkan komponen, karena saya memerlukan cara bagi para manajer untuk mengetahui objek apa yang perlu logika komponen apa yang harus dijalankan (jika tidak saya hanya akan menghapus komponen sepenuhnya dan dorong logikanya pembaruan ke manajer).
- Apakah ini (memiliki
ObjectProperty
,ObjectComponent
danComponentManager
kelas) over-engineering? - Apa yang akan menjadi alternatif yang baik?
sumber
SizeComponent
banyak - Anda dapat mengasumsikan bahwa sebagian besar objek memiliki ukuran - itu hal-hal seperti rendering, AI dan fisika di mana model komponen digunakan; Ukuran akan selalu berperilaku sama - sehingga Anda dapat membagikan kode itu.RenderingComponent
dan aPhysicsComponent
. Apakah saya terlalu memikirkan keputusan untuk meletakkan properti itu? Haruskah saya hanya memasukkannya ke dalam salah satu, lalu minta objek lain untuk komponen yang memiliki properti yang dibutuhkan?PhysicalStateInstance
(satu per objek) di sampingGravityPhysicsShared
(satu per game); namun saya tergoda untuk mengatakan ini merambah ke ranah euforia arsitek, jangan membuat diri Anda berlubang (persis seperti yang saya lakukan dengan sistem komponen pertama saya). CIUMAN.Jawaban:
Jawaban sederhana untuk pertanyaan pertama Anda adalah Ya, Anda sudah selesai merancang desain. 'Seberapa jauh saya memecah hal-hal?' pertanyaan sangat umum ketika langkah berikutnya diambil dan objek pusat (biasanya disebut Entitas) dihapus.
Ketika Anda mendobrak objek ke tingkat terperinci sehingga memiliki ukuran sendiri maka desainnya sudah terlalu jauh. Nilai data sendiri bukan komponen. Ini adalah tipe data bawaan dan sering dapat disebut dengan tepat apa yang Anda sebut sebagai properti. Properti bukan komponen, tetapi komponen yang mengandung properti.
Jadi, berikut adalah beberapa garis panduan yang saya coba dan ikuti ketika mengembangkan dalam sistem komponen:
Jadi dengan pedoman komponen tidak menjadi struktur, SizeComponent telah dipecah terlalu jauh. Ini hanya berisi data dan apa yang menentukan ukuran sesuatu dapat bervariasi. Misalnya, dalam komponen rendering itu bisa berupa skalar 1d atau vektor 2 / 3d. Dalam komponen fisika, itu bisa menjadi volume pembatas objek. Dalam item inventaris, bisa jadi berapa banyak ruang yang digunakan pada kisi 2D.
Coba dan tarik garis yang baik antara teori dan kepraktisan.
Semoga ini membantu.
sumber
Anda sudah menerima jawaban, tetapi inilah tikaman saya di CBS. Saya menemukan bahwa
Component
kelas generik memiliki beberapa keterbatasan, jadi saya pergi dengan desain yang dijelaskan oleh Radical Entertainment di GDC 2009, yang menyarankan pemisahan komponen menjadiAttributes
danBehaviors
. (" Teori dan Praktek Arsitektur Komponen Objek Permainan ", Marcin Chady)Saya menjelaskan keputusan desain saya dalam dokumen dua halaman. Saya hanya akan memposting tautan karena terlalu lama untuk menempelkan semuanya di sini. Saat ini hanya mencakup komponen logika (bukan komponen rendering dan fisika juga), tetapi harus memberi Anda gambaran tentang apa yang saya coba lakukan:
► http://www.pdf-archive.com/2012/01/08/entity-component-system/preview/page/1
Berikut kutipan dari dokumen:
Sunting: Dan inilah diagram hubungan yang menunjukkan bagaimana komponen berkomunikasi satu sama lain:
Detail implementasi: level entitas
EventManager
hanya dibuat jika digunakan. TheEntity
kelas hanya menyimpan pointer keEventManager
yang diinisialisasi hanya jika beberapa permintaan komponen itu.Sunting: Pada pertanyaan lain saya memberikan jawaban yang mirip dengan yang ini. Anda dapat menemukannya di sini untuk penjelasan yang lebih baik tentang sistem:
► /gamedev//a/23759/6188
sumber
Ini benar-benar tergantung pada properti yang Anda butuhkan dan di mana Anda membutuhkannya. Jumlah memori yang akan Anda miliki dan kekuatan / jenis pemrosesan yang akan Anda gunakan. Saya telah melihat dan mencoba melakukan hal berikut:
Prinsip-prinsip ini memiliki keterbatasan. Tentu saja Anda harus mendorong geometri ke renderer tetapi Anda mungkin tidak ingin mengambilnya dari sana. Master geometri akan disimpan dalam mesin fisika dalam kasus di mana deformasi terjadi di sana dan disinkronkan dengan renderer (dari waktu ke waktu tergantung pada jarak objek). Jadi dengan cara apa pun Anda akan menduplikasinya.
Tidak ada sistem yang sempurna. Dan beberapa permainan akan lebih baik dengan sistem yang lebih sederhana sementara yang lain akan membutuhkan sinkronisasi yang lebih kompleks di seluruh sistem.
Pada awalnya pastikan semua properti dapat diakses secara sederhana dari komponen Anda sehingga Anda dapat mengubah cara Anda menyimpan properti secara transparan setelah Anda mulai memperbaiki sistem Anda.
Tidak ada salahnya menyalin beberapa properti. Jika beberapa komponen perlu memiliki salinan lokal, terkadang lebih efisien untuk menyalin dan menyinkronkan daripada mengakses nilai "eksternal"
Sinkronisasi juga tidak harus terjadi setiap frame. Beberapa komponen dapat disinkronkan lebih jarang daripada yang lain. Komponen render seringkali merupakan contoh yang baik. Yang tidak berinteraksi dengan pemain dapat disinkronkan lebih jarang, sama seperti yang jauh. Yang jauh dan di luar bidang kamera dapat disinkronkan bahkan lebih jarang.
Ketika datang ke komponen ukuran Anda mungkin dapat dibundel dalam komponen posisi Anda:
Alih-alih ukuran Anda bahkan bisa menggunakan pengubah ukuran, itu mungkin datang lebih mudah.
Untuk menyimpan semua properti dalam sistem penyimpanan properti generik ... Saya tidak yakin Anda menuju ke arah yang benar ... Fokus pada properti yang merupakan inti permainan Anda dan buat komponen yang menggabungkan sebanyak mungkin properti terkait. Selama Anda abstrak akses ke properti ini dengan benar (melalui getter dalam komponen yang membutuhkannya misalnya), Anda harus dapat memindahkan, menyalin, dan menyinkronkannya nanti, tanpa melanggar terlalu banyak logika.
sumber
Jika komponen dapat ditambahkan secara sewenang-wenang ke entitas, maka Anda perlu cara untuk menanyakan apakah komponen tertentu ada dalam suatu entitas dan untuk mendapatkan referensi. Jadi, Anda mungkin mengulangi daftar objek yang berasal dari ObjectComponent hingga Anda menemukan yang Anda inginkan, dan mengembalikannya. Tetapi Anda akan mengembalikan objek dengan tipe yang benar.
Dalam C ++ atau C # ini biasanya berarti Anda akan memiliki metode templat pada entitas seperti
T GetComponent<T>()
. Dan begitu Anda memiliki referensi itu, Anda tahu persis data anggota apa yang dimilikinya, jadi akses saja secara langsung.Dalam sesuatu seperti Lua atau Python Anda tidak perlu memiliki jenis objek yang eksplisit, dan mungkin juga tidak peduli. Tetapi sekali lagi, Anda bisa mengakses variabel anggota dan menangani pengecualian yang muncul karena mencoba mengakses sesuatu yang tidak ada.
Menanyakan properti objek secara eksplisit terdengar seperti menduplikasi pekerjaan yang dapat dilakukan bahasa untuk Anda, baik pada waktu kompilasi untuk bahasa yang diketik secara statis atau pada saat dijalankan untuk yang diketik secara dinamis.
sumber
Masalahnya adalah bahwa RenderingComponent menggunakan posisi, tetapi PhysicsComponent menyediakannya . Anda hanya perlu cara untuk memberi tahu setiap komponen pengguna penyedia mana yang digunakan. Idealnya dengan cara agnostik, kalau tidak akan ada ketergantungan.
Tidak ada aturan umum. Tergantung pada properti tertentu (lihat di atas).
Buat game dengan arsitektur berbasis komponen yang jelek tapi kemudian refactor.
sumber
PhysicsComponent
harus saya lakukan. Saya melihatnya mengelola simulasi objek dalam lingkungan fisik, yang membawa saya ke kebingungan ini: Tidak semua hal yang perlu dirender perlu disimulasikan, jadi sepertinya salah jika saya menambahkanPhysicsComponent
ketika saya menambahkanRenderingComponent
karena mengandung posisi yangRenderingComponent
menggunakan. Saya dapat dengan mudah melihat diri saya berakhir dengan web komponen yang saling terhubung, artinya semua / sebagian besar perlu ditambahkan ke setiap entitas.Usus Anda yang memberitahu Anda bahwa memiliki
ThingProperty
,ThingComponent
, danThingManager
untuk setiapThing
jenis komponen sedikit berlebihan. Saya pikir itu benar.Tapi, Anda perlu beberapa cara untuk melacak komponen terkait dalam hal sistem apa yang menggunakannya, entitas apa yang mereka miliki, dll.
TransformProperty
akan menjadi yang sangat umum. Tapi siapa yang bertanggung jawab atas itu, sistem rendering? Sistem fisika? Sistem suara? Mengapa suatuTransform
komponen bahkan perlu memperbarui sendiri?Solusinya adalah menghapus segala jenis kode dari properti Anda di luar getter, setter, dan inisialisasi. Komponen adalah data, yang digunakan oleh sistem dalam game untuk melakukan berbagai tugas seperti rendering, AI, pemutaran suara, pergerakan, dll.
Baca tentang Artemis: http://piemaster.net/2011/07/07/entity-component-artemis/
Lihatlah kodenya dan Anda akan melihat bahwa itu didasarkan pada Sistem yang menyatakan dependensi mereka sebagai daftar
ComponentTypes
. Anda menulis masing-masingSystem
kelas Anda dan dalam metode konstruktor / init mendeklarasikan tipe yang bergantung pada sistem.Selama pengaturan untuk level atau yang lainnya, Anda membuat entitas Anda dan menambahkan komponen ke dalamnya. Setelah itu Anda memberi tahu entitas tersebut untuk melaporkan kembali ke Artemis, dan Artemis kemudian mencari tahu berdasarkan komposisi entitas yang sistem mana yang akan tertarik mengetahui tentang entitas itu.
Kemudian selama fase pembaruan dari loop Anda
System
, sekarang Anda memiliki daftar entitas apa yang akan diperbarui. Sekarang Anda dapat memiliki rincian komponen sehingga Anda dapat merancang sistem gila, entitas membangun keluar dariModelComponent
,TransformComponent
,FliesLikeSupermanComponent
, danSocketInfoComponent
, dan melakukan sesuatu yang aneh seperti make piring terbang yang lalat antara klien terhubung ke permainan multiplayer. Oke, mungkin bukan itu, tetapi idenya adalah membuat semuanya terpisah dan fleksibel.Artemis tidak sempurna, dan contoh-contoh di situs ini sedikit mendasar, tetapi pemisahan kode dan data sangat kuat. Ini juga baik untuk cache Anda jika Anda melakukannya dengan benar. Artemis mungkin tidak melakukannya dengan benar di depan itu, tapi itu baik untuk dipelajari.
sumber