Bileşen varlık sistemi - Güncellemeler ve çağrı siparişleri


10

Bileşenlerin her kareyi güncelleyebilmeleri (ve bu işlevselliği gerekmeyen bileşenlerin dışında bırakabilmeleri) için bir UpdateComponent bileşeni yapma fikrim var. MovableComponent(Hızı tutan) gibi diğer bileşenler IUpdatablesoyut sınıftan miras alır . Bu MovableComponentbir Update(gametime dt)yöntem ve bir işaretçi RegisterWithUpdater()veren başka bir yöntem uygulamak için zorlar . Birçok bileşen bunu yapabilir ve daha sonra kim veya ne olduklarına dikkat etmeden tüm yöntemlerini çağırabilir .UpdateComponentMovableComponentUpdateComponentUpdate(gametime dt)

Sorularım:

  1. Bu normal veya herkes tarafından kullanılan bir şey gibi mi görünüyor? Bu konuda hiçbir şey bulamıyorum.
  2. Konum değişikliği sonrasında fizik gibi bileşenlere nasıl bir emir verebilirim? Bu bile gerekli mi?
  3. Her kareyi işlemesi gereken bileşenlerin aslında işlenmesini sağlamanın diğer yolları nelerdir?

DÜZENLEME
Ben varlık yöneticisine güncellenebilir türlerin bir listesini vermek nasıl düşüneceğim düşünüyorum. Daha sonra, bu türdeki TÜM bileşenler varlık başına yönetmek yerine güncellenebilir (yine de sistemimdeki dizinler).

Hala. Sorularım benim için geçerli. Bunun makul / normal olup olmadığını veya başkalarının ne yapmaya meyilli olduğunu bilmiyorum.

Ayrıca, Insomniac insanlar harika! /DÜZENLE

Önceki örnek için kaynayan kod:

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_;
};

Güncellenemeyen bir bileşene örnek var mı? Bu oldukça işe yaramaz görünüyor. Güncelleme işlevini bileşene sanal işlev olarak yerleştirin. Sonra sadece "UpdateComponent" için gerek yok, varlık tüm bileşenleri güncelleyin
Maik Semder

Bazı bileşenler daha çok veri tutuculara benzer. PositionComponent gibi. Birçok nesnenin bir konumu olabilir, ancak durağansa, çoğunluk olabilir, tüm bu ekstra sanal çağrılar oluşabilir. Veya bir HealthComponent deyin. Bunun her karede bir şey yapmasına gerek yoktur, sadece gerektiğinde değiştirilir. Belki de ek yük o kadar da kötü değil ama UpdateComponent'im HER bileşende Update () bulunma girişimiydi.
ptpaterson

5
Yalnızca verileri tutan ve zaman içinde değiştirecek işlevselliği olmayan bir bileşen tanım gereği bir bileşen değildir. Bileşende zaman içinde değişen bazı işlevler olmalıdır, bu nedenle bir güncelleme işlevine ihtiyaç duyar. Bileşeninizin bir güncelleme işlevine ihtiyacı yoksa, bunun bir bileşen olmadığını bilirsiniz ve tasarımı yeniden düşünmelisiniz. Sağlık bileşenindeki bir güncelleme işlevi mantıklıdır, örneğin NPC'nizin bir süre hasar görmesini istersiniz.
Maik Semder

@Maik Demek istediğim hiç değişmeyecek / değiştiremeyecek bileşenler değildi. Kabul ediyorum aptalca. Her kareyi güncellemelerine gerek yoktur, gerektiğinde bilgilerini değiştirmek için bilgilendirilirler. Zaman içindeki sağlık durumunda, güncellemenin YAPILDIĞI bir sağlık bonusu bileşeni olacaktır. İkisini birleştirmek için herhangi bir neden olduğunu düşünmüyorum.
ptpaterson

Ayrıca yayınladığım kodun sadece UpdateComponent kavramını açıklamak için gerekenlere sahip olduğunu belirtmek isterim. Bileşenler arasındaki diğer tüm iletişim biçimlerini hariç tutar.
ptpaterson

Yanıtlar:


16

Bileşen sisteminin birincil faydalarından biri, önbellek desenlerinden yararlanabilme yeteneğidir - iyi icache ve tahmin, aynı kodu tekrar tekrar çalıştırdığınız için, iyi dcache çünkü nesneleri homojen havuzlarda ayırabileceğiniz ve herhangi, sıcak kal.

Bileşenlerinizi yapılandırma şekliniz bu avantaj tamamen kaybolur ve aslında çok daha fazla sanal çağrı ve vesilelerle daha fazla nesne yaptığınız için miras tabanlı bir sistemle karşılaştırıldığında bir performans yükümlülüğü haline gelebilir.

Yapmanız gereken, tür başına havuzları saklamak ve güncellemeleri gerçekleştirmek için her türü bağımsız olarak yinelemek.

Bu normal veya herkes tarafından kullanılan bir şey gibi mi görünüyor? Bu konuda hiçbir şey bulamıyorum.

Büyük oyunlarda yaygın değildir, çünkü avantajlı değildir. Birçok oyunda yaygındır, ancak teknik olarak ilginç değildir, bu yüzden kimse bu konuda yazmaz.

Konum değişikliği sonrasında fizik gibi bileşenlere nasıl bir emir verebilirim? Bu bile gerekli mi?

C ++ gibi dillerde kod yürütmek için doğal bir yol vardır: ifadeleri bu sırayla yazın.

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

Gerçekte, bu mantıklı değil çünkü sağlam bir fizik sistemi bu şekilde yapılandırılmamıştır - tek bir fizik nesnesini güncelleyemezsiniz. Bunun yerine, kod daha çok şöyle görünecektir:

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

Teşekkürler. Tüm projeye veri odaklı (veri güdümlü değil) düşünülerek başladım, önbellek hatalarını önledim ve bu gibi. Ama kodlamaya başladığımda sadece nokta com çalıştı bir şey yapmaya karar verdim. Görünüşe göre işler benim için zorlaştı. Ve ciddi olarak, bu uykusuzluk makalesi harikaydı!
ptpaterson

@Joe +1 çok iyi bir cevap için. Her ne kadar bir icache ve dcache olduğunu bilmek istiyorum. Teşekkürler
Ray Dey

Komut önbelleği ve veri önbelleği. Bilgisayar mimarisindeki giriş metinleri bunları kapsamalıdır.

@ptpaterson: Uykusuzluk sunumunda küçük bir hata olduğunu unutmayın - bileşen sınıfının liste dizinini içermesi gerekir veya liste dizinleri için havuz dizinlerinin ayrı bir eşleştirilmesi gerekir.

3

Bahsettiğin şey makul ve oldukça yaygın. Bu size biraz daha bilgi verebilir.


Sanırım bu makaleye birkaç hafta önce rastladım. Bileşen tabanlı bir varlık sisteminin birkaç basit versiyonunu birlikte kodlayabildim, her biri farklı şeyler denediğimde çok farklı. Tüm makaleleri ve örnekleri istediğim ve yapabildiğim bir şeyde bir araya getirmeye çalışmak. Teşekkürler!
ptpaterson

0

Bu yaklaşımları seviyorum:

Kısaca: Güncelleme davranışını bileşenler içinde tutmaktan kaçının. Bileşenler davranış değildir . Davranış (güncellemeler dahil) bazı tek örnekli alt sistemlerde uygulanabilir. Bu yaklaşım, birden çok bileşen için benzer davranışların toplu işlenmesine de yardımcı olabilir (belki bileşen verilerinde parallel_for veya SIMD talimatları kullanarak).

IUpdatable fikri ve Güncelleme (gametime dt) yöntemi biraz fazla kısıtlayıcı görünüyor ve ek bağımlılıklar getiriyor. Alt sistemler yaklaşımını kullanmıyorsanız iyi olabilir, ancak bunları kullanırsanız, IUpdatable yedekli bir hiyerarşi düzeyidir. Sonuçta, MovingSystem, bu bileşenleri içeren tüm varlıklar için Konum ve / veya Hız bileşenlerini doğrudan güncellemesi gerektiğini bilmelidir, bu nedenle bazı ara IUpdatable bileşenlerine gerek yoktur.

Ancak Güncellenebilir bileşeni, Konum ve / veya Hız bileşenlerine sahip olmalarına rağmen bazı varlıkları güncellemeyi atlamak için bir mekanizma olarak kullanabilirsiniz. Güncellenebilir bileşen, ayarlanabilen falseve her Güncelleştirilebilir farkında alt sisteme bu özel varlığın şu anda güncelleştirilmemesi gerektiğini bildiren bir bool bayrağı içerebilir (bu bağlamda, Dondurucu bileşen için daha uygun bir ad gibi görünmektedir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.