I am terrible at this (oop code design)

Started by
4 comments, last by CDProp 15 years, 2 months ago
I am creating a game that is somewhat complex (for me). It has similar mechanics to Asteroids, but with all different sorts of enemies and power-ups and that sort of thing. It has multiple levels. Each level is a very large, and so I divide it up with a quadtree. Collision is handled with swept sphere tests, and there is elastic collision response, particle systems for explosions, etc. You get the idea. Nothing ground-breaking. I'm mostly doing this in hopes of having code I can re-use for more-complicated things later on. I'm having a bit of trouble organizing my code. I have a few different systems, like the RenderingEngine, the InputManager, etc., which are implemented as classes, but I only need one instance of each of these systems. I am not using singletons because I understand a bit about the pitfalls of those. However, these systems do need to communicate with one another sometimes. For instance, my GameWindow might need to know if the Enter button has been pressed, so it needs to get that information from the InputManager somehow. So my basic solution for this was to create an App class which has, as members, a RenderingEngine*, an InputManager*, etc. In turn, each of these classes has an App* that points back to the App that owns it. So, if the GameWindow needs to know if the Enter button has been pressed, I would do something like this: m_pApp->GetInputManager()->IsKeyPressed( ENTER_KEY ); One reason why I am a bit uncomfortable with this is that not only is the GameWindow class dependent on the App class, and vice-versa, but it is also dependent on the InputManager* class as well. This was sort of a nightmare, as far as includes and headers were concerned. I eventually got it to compile, but it took a lot of work and gave me a generally bad feeling. One thing that "feels" better, even if it's not, is creating an App::IsKeyDown() method, and getting rid of the App::GetInputManager() method. That way, the other classes don't have access to the InputManager class at all, nor would it need it. However, creating accessors for everything that these classes can do will take a lot of work, and I don't know if I'm even on the right track.
Advertisement
i would probably do somekind of event system... since the GameWindow doesnt need to know about the "inputManager" i would simply do an OnKeyDown() function in GameWindow that the inputManager calls... something like

inputManager.AddEventListener("KEY_DOWN", boost::bind(&GameWindow::OnKeyDown, gameWindow));

there are alot of ways to implement this...

another example...

inputManager.KeyDownEvent += new EventHandler(boost::bind(&GameWindow::OnKeyDown, gameWindow));

EDIT:

i would recommend this library for event handling...

http://www.gamedev.net/community/forums/topic.asp?topic_id=456646
As far as includes go, if you make a global app class that has a lot of functions which all sorts of other objects should have access to, then you can put the app header in the .cpp files of the objects but not in their header files. If you do that it's relatively easy to avoid include problems.

On the subject of OOP design, eh, while there might be better solutions, I don't think a global app class is all that bad. Particularly if you've got RenderEngine and InputManager and ObjectManager, etc. What you can do is identify places where you can remove dependencies. You can also pass references to all the managers around to each other, then they can talk to each other without requiring a global app class. At the end of the day though, the point is to write a game, so spending too much time focusing on OOP design can slow you down. I'm a sucker for over-designing things myself. =(
It sounds to me like the problem might be that you're trying too hard to think of your project in terms of "systems". :) Anyway, the normal way to communicate from one function to the next is to use the parameters and return value of the function. Tell, don't ask. There's nothing that prevents an object from passing itself as a parameter, BTW.
Having a queue of game_events and passing it as a parameter to each object that needs to read it isn't a bad idea.

That way you'll decouple "specific" hardware/network input from game logic.
[size="2"]I like the Walrus best.
Woops, totally forgot about this thread. Thanks for all of the help, guys. I'm re-designing the code based on some of the suggestions here and I'm already pretty happy with it.

This topic is closed to new replies.

Advertisement