Sistem entitas komponen - Pembaruan dan pesanan panggilan


10

Untuk mendapatkan komponen agar dapat memperbarui setiap frame (dan meninggalkan fungsi ini dari komponen yang tidak perlu), saya mendapat ide untuk membuat komponen UpdateComponent. Komponen lain seperti MovableComponent(yang memiliki kecepatan) akan mewarisi dari IUpdatablekelas abstrak. Ini memaksa MovableComponentuntuk menerapkan Update(gametime dt)metode dan lainnya RegisterWithUpdater()yang memberikan UpdateComponentpointer ke MovableComponent. Banyak komponen dapat melakukan ini dan kemudian UpdateComponentdapat memanggil semua Update(gametime dt)metode mereka tanpa harus peduli tentang siapa atau apa mereka.

Pertanyaan saya adalah:

  1. Apakah ini tampak seperti sesuatu yang normal atau digunakan oleh siapa pun? Saya tidak dapat menemukan apa pun tentang masalah ini.
  2. Bagaimana saya bisa mempertahankan pesanan pada komponen-komponen seperti fisika lalu posisi berubah? Apakah ini perlu?
  3. Apa cara lain untuk memastikan bahwa komponen yang harus diproses setiap frame sebenarnya diproses?

EDIT
Saya pikir saya akan mempertimbangkan bagaimana memberikan daftar jenis entitas yang dapat diupdate oleh manajer entitas. Kemudian SEMUA komponen jenis itu dapat memperbarui daripada mengaturnya per entitas (yang hanya indeks di sistem saya saja).

Masih. Pertanyaan saya tetap valid bagi saya. Saya tidak tahu apakah ini masuk akal / normal, atau apa yang cenderung dilakukan orang lain.

Juga, orang-orang di Insomniac luar biasa! / EDIT

Kode rebus untuk contoh sebelumnya:

class IUpdatable
{
public:
    virtual void Update(float dt) = 0;
protected:
    virtual void RegisterAsUpdatable() = 0;
};

class Component
{
    ...
};

class MovableComponent: public Component, public IUpdatable
{
public:
    ...
    virtual void Update(float dt);
private:
    ...
    virtual void RegisterWithUpdater();
};

class UpdateComponent: public Component
{
public:
    ...
    void UpdateAll();
    void RegisterUpdatable(Component* component);
    void RemoveUpdatable(Component* component);
private:
    ...
    std::set<Component*> updatables_;
};

Apakah Anda memiliki contoh untuk komponen yang tidak dapat diperbarui? Tampaknya itu tidak berguna. Masukkan fungsi pembaruan sebagai fungsi virtual ke dalam komponen. Maka cukup perbarui semua komponen dalam entitas, tidak perlu untuk "UpdateComponent"
Maik Semder

Beberapa komponen lebih seperti pemegang data. Seperti PositionComponent. Banyak objek dapat memiliki posisi, tetapi jika mereka diam, yang bisa menjadi mayoritas, semua panggilan virtual tambahan dapat membangun. Atau katakanlah HealthComponent. Itu tidak perlu melakukan apa pun setiap frame, cukup dimodifikasi ketika perlu. Mungkin overhead tidak terlalu buruk tetapi UpdateComponent saya adalah upaya untuk tidak memiliki Update () di setiap komponen.
ptpaterson

5
Komponen yang hanya menyimpan data dan tidak ada fungsi untuk mengubahnya dari waktu ke waktu adalah menurut definisi bukan komponen. Harus ada beberapa fungsi dalam komponen yang berubah seiring waktu, oleh karena itu perlu fungsi pembaruan. Jika komponen Anda tidak memerlukan fungsi pembaruan, maka Anda tahu itu bukan komponen dan Anda harus memikirkan kembali desain. Fungsi pembaruan dalam komponen kesehatan masuk akal, misalnya Anda ingin NPC Anda pulih dari kerusakan selama beberapa waktu.
Maik Semder

@Maik Maksud saya BUKAN adalah komponen yang tidak akan pernah / tidak pernah bisa berubah. Saya setuju itu konyol. Mereka hanya tidak perlu memperbarui setiap frame, melainkan diberitahukan untuk mengubah info mereka saat diperlukan. Dalam hal kesehatan dari waktu ke waktu, akan ada komponen bonus kesehatan yang TIDAK memiliki pembaruan. Saya tidak berpikir ada alasan untuk menggabungkan keduanya.
ptpaterson

Saya juga ingin mencatat bahwa kode yang saya posting hanya memiliki apa yang diperlukan untuk menjelaskan konsep UpdateComponent. Tidak termasuk semua bentuk komunikasi lainnya antara komponen.
ptpaterson

Jawaban:


16

Salah satu manfaat utama dari sistem komponen adalah kemampuan untuk mengambil keuntungan dari pola caching - icache dan prediksi yang baik karena Anda menjalankan kode yang sama berulang-ulang, dcache yang baik karena Anda dapat mengalokasikan objek dalam kolam yang homogen dan karena vtable, jika apapun, tetap panas.

Cara Anda menyusun komponen Anda, keuntungan ini hilang sepenuhnya, dan pada kenyataannya dapat menjadi kewajiban kinerja dibandingkan dengan sistem berbasis warisan, karena Anda melakukan lebih banyak panggilan virtual dan lebih banyak objek dengan vtable.

Apa yang harus Anda lakukan adalah menyimpan kumpulan per jenis, dan iterasi setiap jenis secara independen untuk melakukan pembaruan.

Apakah ini tampak seperti sesuatu yang normal atau digunakan oleh siapa pun? Saya tidak dapat menemukan apa pun tentang masalah ini.

Ini tidak biasa di permainan besar karena tidak menguntungkan. Ini umum di banyak gim, tetapi secara teknis tidak menarik, jadi tidak ada yang menulis tentang itu.

Bagaimana saya bisa mempertahankan pesanan pada komponen-komponen seperti fisika lalu posisi berubah? Apakah ini perlu?

Kode dalam bahasa seperti C ++ memiliki cara alami untuk memesan eksekusi: ketikkan pernyataan dalam urutan itu.

for (PhysicsComponent *c : physics_components)
    c->update(dt);
for (PositionComponent *c : position_components)
    c->update(dt);

Pada kenyataannya, itu tidak masuk akal karena tidak ada sistem fisika kuat yang terstruktur seperti itu - Anda tidak dapat memperbarui satu objek fisika tunggal. Alih-alih, kodenya akan lebih mirip:

physics_step();
for (PositionComponent *c : position_components)
    c->update(dt);
// Updates the position data from the physics data.

Terima kasih. Saya memulai seluruh proyek ini dengan berorientasi data (tidak sama dengan data didorong) dalam pikiran, mencegah kesalahan cache dan semacamnya. Tapi begitu saya mulai coding saya memutuskan hanya untuk membuat sesuatu yang berfungsi dot com. Ternyata itu membuatku lebih sulit. Dan untuk yang serius, artikel insomnia itu hebat!
ptpaterson

@ Jo +1 untuk jawaban yang sangat bagus. Meskipun saya ingin tahu apa itu icache dan dcache. Terima kasih
Ray Dey

Cache instruksi dan cache data. Teks pengantar pada arsitektur komputer harus mencakup mereka.

@ptpaterson: Perhatikan bahwa ada kesalahan kecil dalam presentasi Insomniac - kelas komponen harus berisi daftar indeksnya, atau Anda memerlukan pemetaan indeks kumpulan yang terpisah untuk membuat daftar indeks.

3

Apa yang Anda bicarakan masuk akal dan cukup umum, saya pikir. Ini mungkin memberi Anda informasi lebih lanjut.


Saya pikir saya menemukan artikel itu beberapa minggu yang lalu. Saya sudah bisa mengkodekan bersama beberapa versi yang sangat sederhana dari sistem entitas berbasis komponen, masing-masing sangat berbeda ketika saya mencoba berbagai hal. Mencoba menyatukan semua artikel dan contoh menjadi sesuatu yang saya inginkan dan dapat saya lakukan. Terima kasih!
ptpaterson

0

Saya suka pendekatan ini:

Singkatnya: Hindari menjaga perilaku pembaruan dalam komponen. Komponen bukan perilaku. Perilaku (termasuk pembaruan) dapat diimplementasikan dalam beberapa subsistem instance-tunggal. Pendekatan itu mungkin juga membantu untuk batch-proses perilaku serupa untuk banyak komponen (mungkin menggunakan parallel_for atau instruksi SIMD pada data komponen).

Metode IUpdatable dan Pembaruan (gametime dt) tampaknya agak terlalu membatasi dan memperkenalkan penambahan tambahan. Mungkin baik-baik saja jika Anda tidak menggunakan pendekatan subsistem, tetapi jika Anda menggunakannya, maka IUpdatable adalah tingkat hierarki yang berlebihan. Bagaimanapun, MovingSystem harus tahu bahwa ia harus memperbarui Lokasi dan / atau komponen Velocity secara langsung untuk semua entitas yang memiliki komponen ini, sehingga tidak perlu untuk beberapa komponen IUpdatable menengah.

Tetapi Anda dapat menggunakan komponen yang dapat diupdate sebagai mekanisme untuk melewati pembaruan beberapa entitas meskipun mereka memiliki komponen Lokasi dan / atau Kecepatan. Komponen yang dapat diupdate dapat memiliki flag bool yang dapat diatur ke falsedan yang akan memberi sinyal pada setiap subsistem yang dapat diperbarui yang entitas yang saat ini tidak boleh diperbarui (walaupun dalam konteks seperti itu, Freezable tampaknya lebih sesuai dengan nama untuk komponen).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.