I had a question about game architecture: What is the best way to have different components communicate with each other?
I do really apologize if this question has already been asked a million times, but I can't find anything with exactly the kind of information I'm looking for.
I've been trying to build a game up from scratch (C++ if it matters) and have observed some open source game software for inspiration (Super Maryo Chronicles, OpenTTD and other). I notice that a lot of these game designs use global instances and/or singletons all over the place (for things like render queues, entity managers, video managers, and so forth). I'm trying avoid global instances and singletons and build an engine that is as loosely coupled as possible, but I'm hitting some obstacles that owe to my inexperience in effective design. (Part of the motivation for this project is to address this :) )
I've built a design where I have one main GameCore
object that has members that are analogous to the global instances I see in other projects (ie, it has an input manager, a video manager, a GameStage
object that controls all the entities and game play for whatever stage is currently loaded, etc). The problem is that since everything is centralized in the GameCore
object, I don't have an easy way for different components to communicate with each other.
Looking at Super Maryo Chronicles, for example, whenever a component of the game needs to communicate with another component (ie, an enemy object wants to add itself to the render queue to be be drawn in the render stage), it just talks to the global instance.
For me, I have to have my game objects pass relevant information back to the GameCore
object, so that the GameCore
object can pass that information to the other component(s) of the system that needs it (ie: for the situation above, each enemy object would pass their render information back to the GameStage
object, which would collect it all and pass it back to GameCore
, which would in-turn pass it to the video manager for rendering). This feels like a really horrible design as is, and I was trying to think of a resolution to this. My thoughts on possible designs:
- Global instances (design of Super Maryo Chronicles, OpenTTD, etc)
- Having the
GameCore
object act as a middleman through which all objects communicate (current design described above) - Give components pointers to all other components they will need to talk with (ie, in the Maryo example above, the enemy class would have a pointer to the video object it needs to talk to)
- Break the game into subsystems - For example, have manager objects in the
GameCore
object that handle communication between objects in their subsystem - (Other options? ....)
I imagine option 4 above to be the best solution, but I'm having some trouble designing it... perhaps because I've been thinking in terms of the designs I have seen that use globals. It feels like I'm taking the same problem that exists in my current design and replicating it in each subsystem, just at a smaller scale. For example, the GameStage
object described above is somewhat of an attempt at this, but the GameCore
object is still involved in the process.
Can anyone offer any design advice here?
Thanks!