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
GameCoreobject 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
GameCoreobject 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?