Beim Entwerfen eines Entity-Component-Systems für meine Engine bin ich auf einen kleinen Haken beim Speichern und Abrufen eines bestimmten Komponententyps gestoßen.
Lassen Sie mich zunächst einige Begriffe festlegen, die ich in dieser Frage verwenden werde:
- Ich nenne " Komponente " eine Datenstruktur, die relevante Daten für ein bestimmtes System speichert.
- Ich nenne " System " eine Ansammlung von Methoden und Datenstrukturen, die Komponenten verwenden, um den Spielstatus / die Spielschnittstelle mit dem Benutzer zu aktualisieren.
- Eine " Entität " ist im Grunde nur eine ID, mit der bestimmte Komponenten abgerufen und ihre Daten in der Spielelogik geändert werden.
Jedes System besitzt ein (ID-zugeordnetes) Array seines Komponententyps (z. B. Physik-> Physikkomponente, AI-> AIComponent, Rendering-> RenderingComponent), sodass es effizient über Daten iterieren kann.
Nicht alle Komponenten gehören jedoch speziell einem System. Eine Transformationskomponente speichert beispielsweise die Position, Drehung und Skalierung eines Objekts. Es ist einer der wichtigsten Teile einer Entität (Unity macht es sogar obligatorisch), da es von vielen Systemen verwendet wird, z. B. Physik, KI, Rendering usw.
Dies ist so ziemlich das Problem, mit dem ich konfrontiert bin. Wie kann ich vorgehen, da Transform von vielen anderen Systemen verwendet wird, um eines für jede Komponente zu finden? Eine mögliche Lösung besteht darin, dass jede Komponente ihre eigene Entitäts-ID speichert. Es wäre einfach, eine solche Komponente abzurufen, aber es wäre nicht so effizient, und es würde auch gegen das Konzept einer Komponente als isoliertes und unabhängiges Datenbündel verstoßen, das keine andere kennt.
Gibt es einen geeigneten Weg, um dieses Problem zu lösen? Sollte Transform überhaupt eine Komponente sein?
quelle
Antworten:
Dies ist eine ziemlich breite Frage, deren Antwort stark von Ihrer Architektur abhängt. Ich werde jedoch versuchen, Ihnen eine allgemeine Antwort zu geben.
Ihre Physik- und Rendering-Systeme erfordern sicherlich die Transformation, das KI-System jedoch nicht. Daher ist es sinnvoll, die Transformation in eine eigene Komponentenklasse zu kapseln. Alle derartigen interessierten Systeme würden dieselben Daten verwenden. Daher ist es sinnvoll, dass die Entität einen Zeiger auf das Transformationsobjekt oder eine ID für ein an anderer Stelle gespeichertes Transformationsobjekt hat.
Wenn Sie sich für die letztere Lösung entscheiden, benötigt jedes System, das an einer Transformation interessiert ist, Zugriff auf den Speicherort des Transformationsobjekts.
Wenn Sie die erstere auswählen, muss jedes System lediglich auf die Entität selbst zugreifen und die Transformation anfordern.
Im ersteren Fall besteht das Problem darin, wie Sie jedem System Zugriff auf den Speicher für Transformationen gewähren können, ohne die OOP-Regeln zu verletzen, wenn Sie sich für solche Dinge interessieren.
Der letztere Fall weist keine derartigen Probleme auf, erfordert jedoch das Ändern des Entitätsobjektdesigns, um Zeiger auf Objekte anstelle von IDs von Komponentenobjekten zu speichern.
Meine persönliche Präferenz ist das Entwerfen der Entitätsklasse zum Speichern von Zeigern auf Komponentenobjekte, da dies viele Entwurfsprobleme vereinfacht. Auf diese Weise kann jedes System, das eine Transformation benötigt, diese von der Entität anfordern und ignorieren, wenn dies nicht der Fall ist. Dies ist jedoch mit einem Rechenaufwand verbunden, der Zeigern inhärent ist, dh den Kosten für Cache-Fehlschläge.
Weitere Informationen hierzu finden Sie in dieser ECS-Übersicht .
Letztendlich liegt es an Ihnen, zu entscheiden, was für Sie wichtiger ist: einfache Entwicklung oder Leistung.
Abschließend möchte ich darauf hinweisen, dass Ihre Frage ein hervorragendes Beispiel für die Entwurfsfragen ist, über die ECS-Befürworter nachdenken, und dass es keine endgültige Silberkugel-Lösung gibt.
quelle