(Was ich beschreibe, basiert auf diesem Entwurf: Was ist ein Entity-System-Framework? Scrollen Sie nach unten und Sie werden es finden.)
Ich habe einige Probleme beim Erstellen eines Entity-Component-Systems in C ++. Ich habe meine Komponentenklasse:
class Component { /* ... */ };
Welches ist eigentlich eine Schnittstelle für andere Komponenten erstellt werden. Um eine benutzerdefinierte Komponente zu erstellen, implementiere ich einfach die Schnittstelle und füge die Daten hinzu, die im Spiel verwendet werden:
class SampleComponent : public Component { int foo, float bar ... };
Diese Komponenten werden in einer Entity-Klasse gespeichert, die jeder Entity-Instanz eine eindeutige ID gibt:
class Entity {
int ID;
std::unordered_map<string, Component*> components;
string getName();
/* ... */
};
Komponenten werden der Entität durch Hashing des Komponentennamens hinzugefügt (dies ist wahrscheinlich keine so gute Idee). Wenn ich eine benutzerdefinierte Komponente hinzufüge, wird sie als Komponententyp (Basisklasse) gespeichert.
Jetzt habe ich auf der anderen Seite eine Systemschnittstelle, die eine Node-Schnittstelle verwendet. Die Node-Klasse wird zum Speichern einiger Komponenten einer einzelnen Entität verwendet (da das System nicht an der Verwendung aller Komponenten der Entität interessiert ist). Wenn das System dies update()
tun muss, muss es nur die von ihm gespeicherten Knoten durchlaufen, die aus verschiedenen Entitäten erstellt wurden. So:
/* 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 */
};
Jetzt das Problem: Nehmen wir an, ich erstelle die SampleNodes, indem ich eine Entität an das SampleSystem übergebe. Der SampleNode "prüft" dann, ob die Entität über die erforderlichen Komponenten verfügt, die vom SampleSystem verwendet werden sollen. Das Problem tritt auf, wenn ich auf die gewünschte Komponente in der Entität zugreifen muss: Die Komponente ist in einer Component
Auflistung (Basisklasse) gespeichert , sodass ich nicht auf die Komponente zugreifen und sie auf den neuen Knoten kopieren kann. Ich habe das Problem vorübergehend gelöst, indem ich den Component
Down auf einen abgeleiteten Typ umwandelte, aber ich wollte wissen, ob es eine bessere Möglichkeit gibt, dies zu tun. Ich verstehe, ob dies bedeuten würde, das, was ich bereits habe, neu zu entwerfen. Vielen Dank.
quelle
addComponent()
Methode nicht auch eine Template-Methode sein? Wenn ich ein definiereaddComponent(Component* c)
, werden alle von mir hinzugefügten Unterkomponenten in einemComponent
Zeiger gespeichert undtypeid
beziehen sich immer auf dieComponent
Basisklasse.Chewy hat es richtig gemacht, aber wenn Sie C ++ 11 verwenden, können Sie einige neue Typen verwenden.
Anstatt
const std::type_info*
als Schlüssel in Ihrer Map zu verwenden, können Sie auchstd::type_index
( siehe cppreference.com ) verwenden, einen Wrapper um diestd::type_info
. Warum würdest du es benutzen? Derstd::type_index
speichert tatsächlich die Beziehung mit demstd::type_info
als Zeiger, aber das ist ein Zeiger weniger, über den Sie sich Sorgen machen müssen.Wenn Sie tatsächlich C ++ 11 verwenden, würde ich empfehlen, die
Component
Referenzen in intelligenten Zeigern zu speichern . Die Karte könnte also etwa so aussehen:So können Sie einen neuen Eintrag hinzufügen:
Wo
component
ist der Typstd::shared_ptr<Component>
. Das Abrufen eines Verweises auf einen bestimmten TypComponent
könnte folgendermaßen aussehen:Beachten Sie auch die Verwendung von
static_pointer_cast
anstelle vonstatic_cast
.quelle
cast
. Ich beginne zu denken, dass es unmöglich wäre, dies oder ein ähnliches Systemdesign ohne Abgüsse zu implementieren.Component
Zeigern in einem einzelnen Container müssen diese notwendigerweise auf den abgeleiteten Typ reduziert werden . Wie Chewy betonte, stehen Ihnen jedoch andere Optionen zur Verfügung, für die kein Casting erforderlich ist. Ich selbst sehe nichts "Schlechtes" darin, diese Art von Abgüssen im Design zu haben, da sie relativ sicher sind.