Saya mencoba menerapkan sistem entitas berbasis komponen tetapi saya agak bingung tentang bagaimana saya harus menangani perpesanan. Ada dua masalah yang ingin saya selesaikan sehingga saya dapat menguji sistem. Di bawah ini adalah kode yang saya miliki sejauh ini,
Kelas Entitas:
class Entity{
public:
Entity(unsigned int id):
id_(id)
{};
void handleMessage(BaseMessage &message){
for(auto element: components_){
element.second->handleMessage(message);
}
}
template<class T>
void attachComponent(T *component){
//Consider making safer in case someone tries to attach same component type twice
components_[typeid(T).hash_code()] = component;
}
template<class T>
void detachComponent(void){
components_.erase(typeid(T).hash_code());
}
template<class T>
T* getComponent(void)const{
return *components_.find(typeid(T).hash_code());
}
unsigned int getInstanceID(void)const{
return id_;
}
private:
unsigned int id_;
std::map<size_t, BaseComponent*> components_;
};
Kelas Komponen dan Pesan Dasar:
class BaseComponent{
public:
virtual void handleMessage(BaseMessage &message){};
};
class BaseMessage{
public:
virtual int getType(void) = 0;
};
1. Penanganan Jenis Pesan
Pertanyaan pertama saya adalah bagaimana saya harus menangani berbagai jenis pesan (berasal dari BaseMessage).
Saya telah memikirkan dua cara untuk menangani jenis pesan dari jenis pesan yang diturunkan. Salah satunya adalah untuk menghasilkan hash (yaitu menggunakan FNV) dari string yang menamai jenis pesan dan menggunakan hash untuk menentukan jenis pesan. Jadi handleMessage(BaseMessage &message)
fungsinya, pertama-tama akan mengekstrak hash ini dari pesan dan kemudian melakukan static_cast ke tipe yang sesuai.
Metode kedua adalah menggunakan templat sebagai berikut (mirip dengan attachComponent
metode kelas entitas),
template<class T>
handleMessage(T& message){};
dan membuat spesialisasi untuk setiap jenis pesan yang akan dibuat komponen tertentu.
Apakah ada kekurangan menggunakan metode kedua? Bagaimana dengan kinerja, mengapa saya tidak melihat penggunaan semacam ini lebih sering?
2. Penanganan Input
Pertanyaan kedua saya adalah apa yang akan menjadi cara optimal (dalam hal latensi dan kemudahan penggunaan) untuk menangani input?
Pikiran saya adalah membuat InputHandlerComponent
register yang dengan kelas keyboard untuk mendengarkan penekanan tombol tertentu yang mungkin ditentukan dalam beberapa file. Sebagai contoh
keyboard.register( player.getComponent<InputHandler>() , 'W')
Saya berharap ada panduan yang lebih ringkas untuk sistem berbasis komponen tetapi saya kira ada banyak cara berbeda untuk melakukan hal yang sama. Saya memiliki lebih banyak pertanyaan, tetapi saya pikir akan lebih bijaksana untuk mencoba menerapkan apa yang saya bisa.
sumber
typeid
(lihat Component and ComponentContainer). Pada dasarnya, saya menyimpan "tipe" komponen sebagai integer, saya memiliki integer global yang saya tambahkan per jenis komponen. Dan saya menyimpan komponen dalam array 2d, di mana indeks pertama adalah ID entitas dan indeks ke-2 adalah ID tipe komponen, yaitu komponen [entityId] [componentTypeId]Saya sedang mengerjakan sistem entitas berbasis komponen di C #, tetapi gagasan dan pola umum masih berlaku.
Cara saya menangani jenis pesan adalah bahwa setiap subkelas komponen memanggil
RequestMessage<T>(Action<T> action) where T : IMessage
metode yang dilindungi Komponen . Dalam bahasa Inggris, itu berarti bahwa subkelas komponen meminta jenis pesan tertentu dan menyediakan metode untuk dipanggil ketika komponen menerima pesan jenis itu.Metode itu akan disimpan dan ketika komponen menerima pesan, ia menggunakan refleksi untuk mendapatkan jenis pesan, yang kemudian digunakan untuk mencari metode terkait dan memintanya.
Anda dapat mengganti refleksi dengan sistem apa pun yang Anda inginkan, hash adalah taruhan terbaik Anda. Lihatlah beberapa pola pengiriman dan pengunjung untuk beberapa ide lain.
Sebagai masukan, saya memilih untuk melakukan sesuatu yang sama sekali berbeda dari apa yang Anda pikirkan. Input handler akan secara terpisah mengonversi input keyboard / mouse / gamepad menjadi enumerasi bendera (bitfield) dari tindakan yang mungkin (MoveForward, MoveBackwards, StrafeLeft, Use, dll.) Berdasarkan pada pengaturan pengguna / apa yang telah dicolokkan pemain ke komputer. Setiap komponen mendapatkan
UserInputMessage
setiap bingkai yang berisi bitfield dan sumbu tampilan pemain sebagai vektor 3d (mengarahkan pengembangan menuju penembak orang pertama). Ini juga membuatnya mudah untuk membiarkan pemain mengubah binding utama mereka.Seperti yang Anda katakan di akhir pertanyaan Anda, ada banyak cara berbeda untuk menciptakan sistem entitas berbasis komponen. Saya telah mengarahkan sistem saya ke permainan yang saya buat, jadi tentu saja beberapa hal yang saya lakukan mungkin tidak masuk akal dalam konteks, katakanlah, sebuah RTS, tapi itu masih sesuatu yang telah diterapkan dan telah bekerja untuk saya sejauh ini.
sumber