Kita mulai dari pendekatan sistem-komponen-entitas dasar .
Mari kita membuat kumpulan (istilah yang berasal dari artikel ini ) hanya dari informasi tentang jenis komponen . Ini dilakukan secara dinamis pada saat runtime, sama seperti kita akan menambah / menghapus komponen ke entitas satu per satu, tapi mari kita beri nama lebih tepatnya karena ini hanya tentang jenis informasi.
Kemudian kami membangun entitas yang menentukan kumpulan untuk masing-masing. Setelah kami membuat entitas, kumpulannya tidak dapat diubah yang artinya kami tidak dapat memodifikasinya secara langsung, tetapi kami masih dapat memperoleh tanda tangan entitas yang ada untuk salinan lokal (bersama dengan konten), membuat perubahan yang tepat untuknya, dan membuat entitas baru keluar itu.
Sekarang untuk konsep kunci: setiap kali suatu entitas dibuat, ia ditugaskan ke objek yang disebut assemblage bucket , yang berarti bahwa semua entitas dengan tanda tangan yang sama akan berada dalam wadah yang sama (misalnya dalam std :: vector).
Sekarang sistem hanya beralih melalui setiap ember minat mereka dan melakukan pekerjaan mereka.
Pendekatan ini memiliki beberapa keunggulan:
- komponen disimpan dalam beberapa (tepatnya: jumlah ember) potongan memori yang berdekatan - ini meningkatkan keramahan memori dan lebih mudah untuk membuang seluruh kondisi permainan
- komponen proses sistem secara linier, yang berarti peningkatan koherensi cache - bye bye kamus dan lompatan memori acak
- membuat entitas baru semudah memetakan kumpulan ke bucket dan mendorong kembali komponen yang diperlukan ke vektornya
- menghapus entitas semudah satu panggilan ke std :: pindah untuk menukar elemen terakhir dengan yang dihapus, karena pesanan tidak masalah saat ini
Jika kita memiliki banyak entitas dengan tanda tangan yang sama sekali berbeda, manfaat koherensi cache agak berkurang, tetapi saya tidak berpikir itu akan terjadi di sebagian besar aplikasi.
Ada juga masalah dengan pembatalan pointer setelah vektor dialokasikan kembali - ini bisa diselesaikan dengan memperkenalkan struktur seperti:
struct assemblage_bucket {
struct entity_watcher {
assemblage_bucket* owner;
entity_id real_index_in_vector;
};
std::unordered_map<entity_id, std::vector<entity_watcher*>> subscribers;
//...
};
Jadi, setiap kali karena alasan tertentu dalam logika permainan kami, kami ingin melacak entitas yang baru dibuat, di dalam bucket kami mendaftarkan entitas_watcher , dan begitu entitas tersebut harus std :: move'd selama penghapusan, kami mencari pengamat dan memperbarui mereka real_index_in_vector
nilai-nilai baru. Sebagian besar waktu ini hanya memaksakan pencarian kamus tunggal untuk setiap penghapusan entitas.
Apakah ada lagi kelemahan dari pendekatan ini?
Mengapa solusinya tidak disebutkan, meskipun cukup jelas?
EDIT : Saya mengedit pertanyaan untuk "menjawab jawaban", karena komentar tidak cukup.
Anda kehilangan sifat dinamis komponen pluggable, yang dibuat khusus untuk menjauh dari konstruksi kelas statis.
Bukan saya. Mungkin saya tidak menjelaskannya dengan cukup jelas:
auto signature = world.get_signature(entity_id); // this would just return entity_id.bucket_owner->bucket_signature or so
signature.add(foo_component);
signature.remove(bar_component);
world.delete_entity(entity_id); // entity_id would hold information about its bucket owner
world.create_entity(signature); // automatically assigns new entity to an existing or a new bucket
Sesederhana mengambil tanda tangan entitas yang ada, mengubahnya dan mengunggah lagi sebagai entitas baru. Sifat pluggable, dinamis ? Tentu saja. Di sini saya ingin menekankan bahwa hanya ada satu kelas "kumpulan" dan satu "ember". Bucket didorong oleh data dan dibuat saat runtime dalam jumlah yang optimal.
Anda harus melewati semua ember yang mungkin berisi target yang valid. Tanpa struktur data eksternal, deteksi tabrakan bisa sama sulitnya.
Nah, inilah mengapa kita memiliki struktur data eksternal yang disebutkan di atas . Solusinya sesederhana memperkenalkan iterator di kelas Sistem yang mendeteksi kapan harus melompat ke bucket berikutnya. The melompat akan murni transparan untuk logika.