Spiel registrieren Objektkomponenten in Spiel Subsystemen? (Component-based Spiel Object Design)
-
08-10-2019 - |
Frage
Ich erstelle ein komponentenbasiertes Spiel Objektsystem . Einige Tipps:
-
GameObject
ist einfach eine Liste vonComponents
. - Es gibt
GameSubsystems
. Zum Beispiel, Rendering, Physik usw. JederGameSubsystem
enthält Zeiger auf einigeComponents
.GameSubsystem
ist eine sehr leistungsfähige und flexible Abstraktion. es stellt jede Scheibe (oder Aspekt) der Spielwelt
Es ist notwendig, in einem Mechanismus Components
in GameSubsystems
der Registrierung (wenn GameObject
erstellt und zusammengesetzt). Es gibt 4 nähert sich :
- 1: Verantwortungskette Muster. Jeder
Component
wird jedenGameSubsystem
angeboten.GameSubsystem
eine Entscheidung trifft, die registrierenComponents
(und wie sie zu organisieren). Zum Beispiel GameSubsystemRender können Render Komponenten registrieren.
Pro. Components
weiß nichts darüber, wie sie verwendet werden. Low-Kupplung. A. können wir neue GameSubsystem
hinzufügen. Zum Beispiel, lassen Sie uns GameSubsystemTitles hinzufügen, die alle ComponentTitle und Garantien registriert, dass jeder Titel ist einzigartig und bietet Schnittstelle zu Objekten nach Titel Quering. Natürlich ComponentTitle sollte in diesem Fall nicht rewrited oder vererbt werden. B. Wir können bestehende GameSubsystems
reorganisieren. Zum Beispiel GameSubsystemAudio, GameSubsystemRender kann GameSubsystemParticleEmmiter in GameSubsystemSpatial zusammengeführt werden (um alle Audio zu platzieren, emmiter, machen Components
in der gleichen Hierarchie und Verwendung Eltern-relativen Transformationen).
con. Jeder zu jedem Scheck. Sehr innefficient.
con. Subsystems
wissen über Components
.
- 2. Jede
Subsystem
sucht nachComponents
bestimmten Arten
Pro. Eine bessere Leistung als in Approach 1
.
con. weiß Subsystems
noch über Components
.
- 3:
Component
registriert sich inGameSubsystem(s)
. Wir wissen, dass zum Zeitpunkt der Kompilierung, dass es eine GameSubsystemRenderer ist, so lass uns ComponentImageRender wird so etwas wie GameSubsystemRenderer nennen :: Register (ComponentRenderBase *).
Observer Muster.Component
abonniert "update" Veranstaltung (vonGameSubsystem(s)
gesendet).
Pro. Performance. Keine unnötigen Kontrollen wie in Approach 1
und Approach 2
.
con. Components
sind schlecht gekoppelt mit GameSubsystems
.
- 4: Mediator Muster.
GameState
(dieGameSubsystems
enthält) kann implementieren registerComponent (Component *).
Pro. Components
und GameSubystems
wissen nichts voneinander.
con. In C ++ würde es aussehen, wie hässlich und langsam typeid-Schalter.
Fragen:
Welcher Ansatz ist besser und vor allem in komponentenbasierten Design verwendet? Was Praxis sagt? Irgendwelche Vorschläge über (data-driven) Umsetzung von Approach 4
?
Danke.
Lösung
Vote for the third approach.
I am currently working on component-based game object system and i clearly see some of additional advantages of this approach:
The Component is more and more self-sufficing subentity as it depends only on a set of available subsystems (i presume this set is fixed in your project).
Data-driven design is more applicable. Ideally, this way you may design a system where components are completely defined in the terms of data but not C++.
EDIT: One feature i thought about while working on CBGOS. Sometimes it is convenient to have ability to design and construct subsystemless passive components. When this is on your mind the fourth approach is the only way.
Andere Tipps
My approach was to implement the proxy pattern within each subsystem. As each subsystem is only interested in a subset of the total components each entity may contain, The proxy stores pointers to only the components the system cares about, eg, a motion system only cares about position and velocity, so it needs a proxy which stores two pointers, to those components. If the entity is missing one or more of those, then the subsystem will ignore it. If both components are present, then a proxy node is created and added to an internal collection. It is also useful for the proxy to store the unique identifier value for the entity, so that proxies may be added/removed in constant time from each subsystem, should it be necessary.
In such a way, should an entity be required to be removed from the engine, a single message containing the id of the entity can be sent to every subsystem. The proxy can then be removed from each subsystem collection independently.