Saya merancang mesin game untuk game 2D shooter top-down multiplayer, yang saya ingin dapat digunakan kembali secara wajar untuk game top-down shooter lainnya. Saat ini saya sedang memikirkan bagaimana sesuatu seperti sistem entitas di dalamnya harus dirancang. Pertama saya memikirkan hal ini:
Saya memiliki kelas yang disebut EntityManager. Seharusnya menerapkan metode yang disebut Pembaruan dan yang lain disebut Draw. Alasan saya memisahkan Logic dan Rendering adalah karena saya dapat menghilangkan metode Draw jika menjalankan server mandiri.
EntityManager memiliki daftar objek tipe BaseEntity. Setiap entitas memiliki daftar komponen seperti EntityModel (representasi yang dapat ditarik dari suatu entitas), EntityNetworkInterface, dan EntityPhysicalBody.
EntityManager juga memiliki daftar manajer komponen seperti EntityRenderManager, EntityNetworkManager dan EntityPhysicsManager. Setiap manajer komponen menyimpan referensi ke komponen entitas. Ada berbagai alasan untuk memindahkan kode ini dari kelas entitas sendiri dan melakukannya secara kolektif. Misalnya, saya menggunakan perpustakaan fisika eksternal, Box2D, untuk permainan. Di Box2D, Anda pertama-tama menambahkan tubuh dan bentuk ke dunia (dimiliki oleh EntityPhysicsManager dalam kasus ini) dan menambahkan collback callbacks (yang akan dikirim ke objek entitas itu sendiri di sistem saya). Kemudian Anda menjalankan fungsi yang mensimulasikan semua yang ada di sistem. Saya merasa sulit untuk menemukan solusi yang lebih baik untuk melakukan ini daripada melakukannya di manajer komponen eksternal seperti ini.
Pembuatan entitas dilakukan seperti ini: EntityManager mengimplementasikan metode RegisterEntity (entitasClass, pabrik) yang mendaftarkan cara membuat entitas dari kelas itu. Ini juga mengimplementasikan metode CreateEntity (entitasClass) yang akan mengembalikan objek tipe BaseEntity.
Sekarang tiba masalah saya: Bagaimana referensi ke komponen didaftarkan ke manajer komponen? Saya tidak tahu bagaimana saya akan merujuk manajer komponen dari pabrik / penutupan.
sumber
Jawaban:
Sistem harus menyimpan pasangan nilai kunci Entity to Component dalam semacam Map, Object Dictionary, atau Associative Array (tergantung pada bahasa yang digunakan). Selain itu, ketika Anda membuat Objek Entitas Anda, saya tidak akan khawatir tentang menyimpannya di manajer kecuali Anda harus dapat membatalkan pendaftarannya dari salah satu Sistem. Entity adalah gabungan komponen, tetapi ia seharusnya tidak menangani pembaruan komponen apa pun. Itu harus ditangani oleh Sistem. Alih-alih memperlakukan Entitas Anda sebagai kunci yang dipetakan ke semua komponen yang dikandungnya dalam sistem, serta hub komunikasi untuk komponen-komponen tersebut untuk saling berbicara.
Bagian hebat dari model Entity-Component-System adalah Anda dapat mengimplementasikan kemampuan untuk meneruskan pesan dari satu komponen ke komponen entitas yang lain dengan cukup mudah. Ini memungkinkan komponen untuk berbicara dengan komponen lain tanpa benar-benar mengetahui siapa komponen itu atau bagaimana menangani komponen itu berubah. Alih-alih mengirimkan pesan dan membiarkan komponen itu mengubah dirinya sendiri (jika ada)
Misalnya, Sistem Posisi tidak akan memiliki banyak kode di dalamnya, hanya melacak Objek Entitas yang dipetakan ke Komponen Posisi mereka. Tetapi ketika suatu posisi berubah, mereka dapat mengirim pesan kepada Entitas yang terlibat, yang pada gilirannya diserahkan ke semua komponen entitas itu. Posisi berubah karena alasan apa pun? Position System mengirim Entity pesan yang mengatakan bahwa posisi berubah, dan di suatu tempat, komponen rendering gambar entitas itu mendapatkan pesan itu dan memperbarui di mana ia akan menggambar dirinya sendiri berikutnya.
Sebaliknya, Sistem Fisika perlu mengetahui apa yang dilakukan semua objeknya; Itu harus dapat melihat semua objek dunia untuk menguji tabrakan. Ketika tabrakan terjadi, itu memperbarui komponen arah Entitas dengan mengirimkan semacam "Pesan Perubahan Arah" ke entitas alih-alih merujuk ke komponen Entitas secara langsung. Ini memisahkan manajer agar tidak perlu tahu cara mengubah arah dengan menggunakan pesan alih-alih mengandalkan komponen tertentu yang ada di sana (yang mungkin tidak ada sama sekali, dalam hal ini pesan hanya akan jatuh di telinga tuli alih-alih beberapa kesalahan terjadi karena objek yang diharapkan tidak ada).
Anda akan melihat keuntungan besar dari ini karena Anda menyebutkan Anda memiliki Antarmuka Jaringan. Komponen Jaringan akan mendengarkan semua pesan yang masuk yang harus diketahui semua orang. Ia menyukai gosip. Kemudian ketika Sistem Jaringan memperbarui, komponen-komponen Jaringan mengirim pesan-pesan itu ke Sistem Jaringan lain pada mesin klien lain, yang kemudian mengirim ulang pesan-pesan itu ke semua komponen lain untuk memperbarui posisi pemain, dll. Logika khusus mungkin diperlukan sehingga hanya entitas tertentu yang dapat mengirim pesan melalui jaringan tetapi itulah keindahan Sistem, Anda bisa mengendalikannya dengan mendaftarkan hal-hal yang benar.
Pendeknya:
Entity adalah komposisi Komponen yang dapat menerima pesan. Entity dapat menerima pesan, mendelegasikan pesan tersebut ke semua komponennya untuk memperbaruinya. (Posisi berubah Pesan, Arah Perubahan Kecepatan, dll.) Ini seperti kotak surat pusat yang semua komponen dapat dengar satu sama lain alih-alih berbicara langsung satu sama lain.
Komponen adalah bagian kecil dari Entitas yang menyimpan beberapa status entitas. Ini dapat mengurai pesan tertentu dan membuang pesan lainnya. Misalnya, "Komponen Arah" hanya akan peduli tentang "Pesan Perubahan Arah" tetapi tidak "Pesan Perubahan Posisi". Komponen memperbarui status mereka sendiri berdasarkan pesan, dan kemudian memperbarui status komponen lain dengan mengirim pesan dari Sistem mereka.
Sistem mengelola semua komponen dari jenis tertentu, dan bertanggung jawab untuk memperbarui komponen-komponen tersebut di setiap frame, serta mengirim pesan dari komponen yang mereka kelola ke Entitas yang menjadi milik Komponen.
Sistem bisa dapat memperbarui semua komponennya secara paralel, dan menyimpan semua pesan saat digunakan. Kemudian ketika eksekusi semua metode pembaruan Sistem selesai, Anda meminta setiap sistem untuk mengirimkan pesan mereka dalam urutan tertentu. Kontrol pertama mungkin, diikuti oleh Fisika, diikuti oleh arah, posisi, render, dll. Yang penting urutan mana mereka dikirim karena Perubahan Arah Fisika harus Selalu keluar mempertimbangkan perubahan arah berdasarkan kontrol.
Semoga ini membantu. Ini seperti Pola Desain, tapi sangat kuat jika dilakukan dengan benar.
sumber
Saya menggunakan sistem serupa di mesin saya dan cara saya melakukannya adalah setiap Entitas berisi daftar Komponen. Dari EntityManager, saya dapat meminta setiap Entitas dan melihat mana yang berisi Komponen yang diberikan. Contoh:
Jelas ini bukan kode yang tepat (Anda sebenarnya membutuhkan fungsi template untuk memeriksa berbagai jenis komponen, daripada menggunakan
typeof
) tetapi konsepnya ada di sana. Kemudian Anda bisa mengambil hasil itu, referensi komponen yang Anda cari, dan mendaftarkannya ke pabrik Anda. Ini mencegah sambungan langsung antara Komponen dan manajernya.sumber
typedef long long int Entity
; Komponen adalah catatan (mungkin diimplementasikan sebagai kelas objek, atau hanya astruct
) yang memiliki referensi ke Entitas yang dilampirkan; dan Sistem akan menjadi metode atau kumpulan metode. Model ECS tidak terlalu kompatibel dengan model OOP, meskipun Komponen dapat menjadi (kebanyakan) objek data saja, dan Sistem objek tunggal kode-satunya yang keadaannya hidup dalam komponen ... meskipun sistem "hybrid" adalah lebih umum daripada yang "murni", mereka kehilangan banyak manfaat bawaan.1) Metode Pabrik Anda harus memberikan referensi ke EntityManager yang menyebutnya (saya akan menggunakan C # sebagai contoh):
2) Miliki CreateEntity juga menerima id (mis. String, integer, terserah Anda) di samping kelas / jenis entitas, dan secara otomatis mendaftarkan entitas yang dibuat pada Kamus menggunakan id itu sebagai kunci:
3) Tambahkan Getter ke EntityManager untuk mendapatkan entitas apa pun dengan ID:
Dan hanya itu yang Anda butuhkan untuk merujuk Manajer Komponen apa pun dari dalam metode Pabrik Anda. Contohnya:
Selain Id, Anda juga dapat menggunakan semacam properti Tipe (enum khusus, atau hanya mengandalkan sistem tipe bahasa), dan membuat pengambil yang mengembalikan semua BaseEntities dari jenis tertentu.
sumber
typedef unsigned long long int EntityID;
:; idealnya adalah, bahwa setiap Sistem dapat hidup pada CPU atau host yang terpisah, dan hanya perlu mengambil komponen yang relevan dengan / aktif dalam Sistem itu. Dengan objek Entity, seseorang mungkin harus instantiate objek Entity yang sama pada setiap host, membuat penskalaan lebih sulit. Model entitas-komponen-sistem murni membagi pemrosesan melintasi node (proses, CPU, atau host) oleh sistem, bukan oleh entitas, biasanya.