(Apa yang saya jelaskan didasarkan pada desain ini: Apa itu kerangka kerja sistem entitas ? , gulir ke bawah dan Anda akan menemukannya)
Saya mengalami beberapa masalah dalam menciptakan sistem entitas-komponen dalam C ++. Saya memiliki kelas Komponen saya:
class Component { /* ... */ };
Yang sebenarnya merupakan antarmuka, untuk komponen lain yang akan dibuat. Jadi, untuk membuat komponen khusus, saya hanya mengimplementasikan antarmuka dan menambahkan data yang akan digunakan dalam game:
class SampleComponent : public Component { int foo, float bar ... };
Komponen-komponen ini disimpan di dalam kelas Entity, yang memberi setiap instance Entity ID unik:
class Entity {
int ID;
std::unordered_map<string, Component*> components;
string getName();
/* ... */
};
Komponen ditambahkan ke entitas dengan hashing nama komponen (ini mungkin bukan ide yang bagus). Ketika saya menambahkan komponen kustom, itu disimpan sebagai tipe Komponen (kelas dasar).
Sekarang, di sisi lain, saya memiliki antarmuka Sistem, yang menggunakan antarmuka Node di dalamnya. Kelas Node digunakan untuk menyimpan beberapa komponen entitas tunggal (karena Sistem tidak tertarik menggunakan semua komponen entitas). Ketika Sistem harus update()
, hanya perlu mengulang melalui Node yang disimpannya dibuat dari entitas yang berbeda. Begitu:
/* System and Node implementations: (not the interfaces!) */
class SampleSystem : public System {
std::list<SampleNode> nodes; //uses SampleNode, not Node
void update();
/* ... */
};
class SampleNode : public Node {
/* Here I define which components SampleNode (and SampleSystem) "needs" */
SampleComponent* sc;
PhysicsComponent* pc;
/* ... more components could go here */
};
Sekarang masalahnya: katakanlah saya membangun SampleNodes dengan mengirimkan entitas ke SampleSystem. SampleNode kemudian "memeriksa" apakah entitas memiliki komponen yang diperlukan untuk digunakan oleh SampleSystem. Masalahnya muncul ketika saya perlu mengakses komponen yang diinginkan di dalam Entity: komponen disimpan dalam Component
koleksi (kelas dasar), jadi saya tidak dapat mengakses komponen dan menyalinnya ke node baru. Saya telah sementara memecahkan masalah dengan melemparkan Component
ke tipe turunan, tapi saya ingin tahu apakah ada cara yang lebih baik untuk melakukan ini. Saya mengerti jika ini berarti mendesain ulang apa yang sudah saya miliki. Terima kasih.
sumber
addComponent()
metode ini perlu menjadi metode templat juga? Jika saya mendefinisikan aaddComponent(Component* c)
, setiap sub-komponen yang saya tambahkan akan disimpan dalam sebuahComponent
pointer, dantypeid
akan selalu merujuk keComponent
kelas dasar.Chewy benar, tetapi jika Anda menggunakan C ++ 11, Anda memiliki beberapa tipe baru yang dapat Anda gunakan.
Alih-alih menggunakan
const std::type_info*
sebagai kunci di peta Anda, Anda bisa menggunakanstd::type_index
( lihat cppreference.com ), yang merupakan pembungkus di sekitarstd::type_info
. Mengapa Anda menggunakannya? Thestd::type_index
sebenarnya menyimpan hubungan denganstd::type_info
sebagai pointer, tapi itu salah satu pointer kurang bagi Anda untuk khawatir tentang.Jika Anda memang menggunakan C ++ 11, saya akan merekomendasikan menyimpan
Component
referensi di dalam smart pointer. Jadi petanya bisa seperti:Menambahkan entri baru dapat dilakukan:
dimana
component
tipestd::shared_ptr<Component>
. Mengambil referensi ke jenis tertentuComponent
dapat terlihat seperti:Perhatikan juga penggunaan
static_pointer_cast
bukanstatic_cast
.sumber
cast
. Saya mulai berpikir bahwa tidak mungkin untuk mengimplementasikan ini, atau desain sistem serupa tanpa gips.Component
pointer dalam satu wadah tentu perlu melemparkannya ke tipe turunan. Tapi, seperti yang ditunjukkan Chewy, Anda memiliki opsi lain yang tersedia untuk Anda, yang tidak memerlukan casting. Saya sendiri tidak melihat ada yang "buruk" dalam desain jenis ini, karena mereka relatif aman.