I'm creating a component-based game object system. Some tips:
GameObjectis simply a list ofComponents.- There are
GameSubsystems. For example, rendering, physics etc. EachGameSubsystemcontains pointers to some ofComponents.GameSubsystemis a very powerful and flexible abstraction: it represents any slice (or aspect) of the game world.
There is a need in a mechanism of registering Components in GameSubsystems (when GameObject is created and composed). There are 4 approaches:
- 1: Chain of responsibility pattern. Every
Componentis offered to everyGameSubsystem.GameSubsystemmakes a decision whichComponentsto register (and how to organize them). For example, GameSubsystemRender can register Renderable Components.
pro. Components know nothing about how they are used. Low coupling. A. We can add new GameSubsystem. For example, let's add GameSubsystemTitles that registers all ComponentTitle and guarantees that every title is unique and provides interface to quering objects by title. Of course, ComponentTitle should not be rewrited or inherited in this case. B. We can reorganize existing GameSubsystems. For example, GameSubsystemAudio, GameSubsystemRender, GameSubsystemParticleEmmiter can be merged into GameSubsystemSpatial (to place all audio, emmiter, render Components in the same hierarchy and use parent-relative transforms).
con. Every-to-every check. Very innefficient.
con. Subsystems know about Components.
- 2: Each
Subsystemsearches forComponentsof specific types.
pro. Better performance than in Approach 1.
con. Subsystems still know about Components.
- 3:
Componentregisters itself inGameSubsystem(s). We know at compile-time that there is a GameSubsystemRenderer, so let's ComponentImageRender will call something like GameSubsystemRenderer::register(ComponentRenderBase*).
Observer pattern.Componentsubscribes to "update" event (sent byGameSubsystem(s)).
pro. Performance. No unnecessary checks as in Approach 1 and Approach 2.
con. Components are badly coupled with GameSubsystems.
- 4: Mediator pattern.
GameState(that containsGameSubsystems) can implement registerComponent(Component*).
pro. Components and GameSubystems know nothing about each other.
con. In C++ it would look like ugly and slow typeid-switch.
Questions:
Which approach is better and mostly used in component-based design? What Practice says? Any suggestions about (data-driven) implementation of Approach 4?
Thank you.