2017-02-08 3 views
2

Also entwickle ich meine erste Game Engine und ich habe eine Wand getroffen. Derzeit habe ich eine Entity-Basisklasse, die einen Vektor von Komponentenzeigern hat, der Zeiger auf Komponentenobjekte innerhalb einiger Systemmanagerklassen (graphisManager, PhysicsManager usw.) enthält. Hier ist meine aktuellen Entity-Header (abgespeckte auf Hauptproblem zu konzentrieren):Wie man Komponenten in einer Spielengine am besten verwaltet?

Entity.h

class Component; 

namespace BlazeGameWorld 
{ 
    class Entity 
    { 
    public: 
     BlazeFramework::Math::Vector2D position; 

    protected: 
     Vector<Component*> components; 

     static BlazeGraphics::GraphicsManager graphicsManager; 
     static BlazePhysics::PhysicsManager physicsManager; 
     static BlazeInput::InputManager inputManager; 
     //....other managers 

    private: 

     /////////////////////////////////////////////////////////////////////// 

    public: 
     Entity(); 
     ~Entity(); 

     virtual bool Initialize(); 
     virtual bool Shutdown(); 

     virtual void Update() = 0; 

     void AddComponent(Component* p_component); 

     //Part of the broadcast messaging system for components to be able 
     //to talk to one another in a decoupled way. 
     void SendMessage(uint messageID); 

    protected: 

    private: 
    }; 
} 

Wie Sie sehen können, ist die Idee, statische Systemmanager Klassen zu haben, die Zeiger auf den tatsächlichen verwalten Komponenten auf dem Heap. Hier ist ein grober Kopf für die potentielle PhysicsManager Klasse (und es ist ähnlich für die anderen Manager-Klassen):

PhysicsManager.h

class PhysicsComponent; 

namespace BlazePhysics 
{ 
    class PhysicsManager 
    { 
    public: 

    protected: 
     int numPhysicsComponents; 
    private: 
     Vector<PhysicsComponent*> physicsComponents; 

     ///////////////////////////////////////////////////////////// 

    public: 
     PhysicsManager(); 
     ~PhysicsManager(); 

     bool Initialize(); 
     bool Shutdown(); 

     void Update(); 

     template <typename PhysicsComponentType> 
     PhysicsComponentType* CreatePhysicsComponent(); 

    private: 
    }; 

    //template definitions 
    template <typename PhysicsComponentType> 
    PhysicsComponentType* PhysicsManager::CreatePhysicsComponent() 
    { 
     PhysicsComponentType* physicsComponent = new PhysicsComponentType 
     physicsComponents.push_back(physicsComponent); 

     return physicsComponents.at(numPhysicsComponents++); 
    } 
} 

So kann ich speichern Sie alle verschiedenen physicsComponent Zeiger im PhysicsManger Vektor (Zeiger auf CollisionComponents, PositionComponents usw.). Das Problem ist, wenn ich eine Methode aufrufen wollte, die für eine bestimmte Physikkomponente spezifisch ist, kann ich nicht kompilieren. Wenn ich zum Beispiel (in der Update-Schleife für PhysicsManager) die Methode CheckCollision() eines collisionComponents jedes Frame aktualisieren wollte, kann ich nicht einfach in einer for-Schleife physicsComponents.at(i).CheckCollision sagen, weil der Compiler zur Kompilierzeit nicht weiß, was eine CollisionComponent ist. Gibt es eine Möglichkeit, den Typ der Komponente im Array zuerst abzuleiten und dann, wenn sie mit CollisionComponent übereinstimmt, die CheckCollision-Methode aufzurufen? Oder ist es besser, dies zu implementieren, da dies irgendwie klobig erscheint?

+0

Gut, hier eine komponentenbasierte Engine zu sehen, ich arbeite auch an meiner ersten Game Engine mit einer ähnlichen Struktur wie deiner. Allerdings habe ich jedem System eine Referenz der Game Engine übergeben, damit sie die Referenz für den Zugriff auf andere Systeme verwenden kann. Ich weiß nicht, ob es gut ist, aber zumindest funktioniert es. Ich hoffe, hier eine bessere Lösung zu sehen. XD –

+0

Ich bin froh, dass Sie hören, dass die Dinge funktionieren! Ich betrachte einige Lösungen, die ein Array von Arrays der verschiedenen Komponententypen implementieren.Wenn ich herausfinden kann, wie man so etwas implementiert, könnte ich hier eine Lösung veröffentlichen. – Jason

Antwort

2

Entitäten sollten nichts über Ihre Systeme wissen, sie sollten nur eine Sammlung von Komponenten sein. Andernfalls würde der Prozess der Einführung eines anderen Engine-Systems auch eine Änderung der Entity-Klasse erfordern, was dem gesamten Zweck von ECS widerspricht.

Auch Systeme sollten Komponenten überhaupt nicht verwalten. Ein System kann mehrere Komponenten verwenden und viele Systeme können z.B. Positions-/Kollisionsgeometrie-Komponenten.

Also, meiner Meinung nach:

  • Komponenten, sollte idealerweise sein, einfach nur Daten Klassen, während die gesamte Verarbeitung innerhalb der Systeme erfolgt.
  • Entität muss nur eine Möglichkeit zum Hinzufügen und Entfernen von Komponenten bereitstellen, und kann angeben, ob eine bestimmte Komponente vorhanden ist.
  • Eine Art von Entity Manager muss Komponenten auf Cache-freundliche Weise speichern, damit Systeme auf sie zugreifen können, und sollte in der Lage sein, eine Liste von Entitäten mit bestimmten Komponenten/Tags für Systeme bereitzustellen.

So zum Beispiel, wenn Sie Skript Verhalten für einige Einheiten hinzufügen wollen, alles, was Sie tun müssen, ist ScriptComponent und ScriptingSystem hinzuzufügen. Der gesamte vorhandene Code erfordert keine Änderung.

This question hat eine Menge sehr nützlicher Ressourcen zum Thema.

+0

Okay, also solltest du sagen, dass eine Entity-Manager-Klasse dafür zuständig sein sollte, alle Komponenten einer Entität im Spiel zu behandeln? Und dass alle Systeme (graphicsSystem, PhysicsSystem, ScriptingSystem) Komponenten auch ein- und auslagern können? – Jason

+0

@Jason Es könnte (und vielleicht besser) etwas beschreibender sein, aber nicht die Systeme selbst definitiv. Systeme würden im Allgemeinen keine Komponenten hinzufügen/entfernen, Ihre Welt/Szene würde dies tun. Es gibt viele Artikel über ECS und einige Open-Source-Implementierungen, die Sie auf jeden Fall überprüfen sollten. – w1ck3dg0ph3r

+0

@Jason Außerdem gab es ein nettes Gespräch über die Implementierung von ECS (https://www.youtube.com/watch?v=NTWSeQtHZ9M) bei CppCon15 von Vittorio Romeo. – w1ck3dg0ph3r

Verwandte Themen