54
\$\begingroup\$

I just read an answer to a question about structuring game code. It made me wonder about the ubiquitous GameManager class, and how it often becomes an issue in a production environment. Let me describe this.

First, there's prototyping. Nobody cares about writing great code, we just try to get something running to see if the gameplay adds up.

Then there's a greenlight, and in an effort to clean things up, somebody writes a GameManager. Probably to hold a bunch of GameStates, maybe to store a few GameObjects, nothing big, really. A cute, little, manager.

In the peaceful realm of pre-production, the game is shaping up nicely. Coders have proper nights of sleep and plenty of ideas to architecture the thing with Great Design Patterns.

Then production starts and soon, of course, there is crunch time. Balanced diet is long gone, the bug tracker is cracking with issues, people are stressed and the game has to be released yesterday.

At that point, usually, the GameManager is a real big mess (to stay polite).

The reason for that is simple. After all, when writing a game, well... all the source code is actually here to manage the game. It's easy to just add this little extra feature or bugfix in the GameManager, where everything else is already stored anyway. When time becomes an issue, no way to write a separate class, or to split this giant manager into sub-managers.

Of course this is a classical anti-pattern: the god object. It's a bad thing, a pain to merge, a pain to maintain, a pain to understand, a pain to transform.

What would you suggest to prevent this from happening?

EDIT

I know it's tempting to blame the naming. Of course creating a GameManager class ain't such a great idea. But the same thing can happen to a clean GameApplication or GameStateMachine or GameSystem that ends up being the duct-tape-favorite by the end of a project. No matter the naming, you have that class somewhere in your game code, it's just an embryo for now: you just don't know yet what monster it will become. So I'm not expecting "blame the naming" answers. I want a way to prevent this from happening, a coding architure and/or a process a team can follow knowing that this will happen at some point in production. It's just too bad to throw away say, one month of bugfixes and last-minute features, just because all of them are now in one huge unmaintainable manager.

\$\endgroup\$
4
  • \$\begingroup\$ Whether it be called GameManager or ControllerOfTheGame, or whatever you want to call it, I mean avoid a class that is in charge of controlling the logic for the whole game. You know you're doing it when you do it regardless of what you plan on calling it. I think my last game I had a levelcontroller which started off just to hold the state of the level for saving, but if I had stopped and thought about it, it was obvious that this object was meant to handle more detail than it should. \$\endgroup\$
    – brandon
    Apr 16, 2012 at 13:47
  • \$\begingroup\$ @brandon Let me rephrase my question for you: how do you control the logic of the whole game without exposing yourself to the GameManager-effect that I described above? \$\endgroup\$ Apr 16, 2012 at 16:53
  • \$\begingroup\$ Depends on the logic. The obvious stuff like player, enemy, structure, etc that clearly has it's own logic gets put into their respective classes. What you seem to be asking most about is handling the state of the game. There will usually be a class that keeps track of the state of the entire game, but in my experience it's one of the last things you need to worry about when prototyping, and it's purpose should be very clear. Basically you either do some initial planning before prototyping or start from scratch when you start production to avoid using junk classes that were just for testing. \$\endgroup\$
    – brandon
    Apr 16, 2012 at 17:00
  • \$\begingroup\$ Interestingly enough, XNA creates this potential disaster for you. By default, a Game class is created to manage, well, everything. It contains the main update, draw, initialize, and load methods. I'm actually in the process of migrating to a new project because my (not so complex) game became too hard to manage with everything crammed into that class. Furthermore, Microsoft tutorials seem to encourage it. \$\endgroup\$
    – Fibericon
    Jul 8, 2013 at 12:15

5 Answers 5

27
\$\begingroup\$

Then there's a greenlight, and in an effort to clean things up, somebody writes a GameManager. Probably to hold a bunch of GameStates, maybe to store a few GameObjects, nothing big, really. A cute, little, manager.

You know, as I was reading this, I had little alarms going off in my head. An object with the name "GameManager" is never going to be cute, or little. And someone did this to clean up the code? What did it look like before? OK, jokes aside: a class's name should be a clear indication of what the class does, and this should be one thing (aka: single responsibility principle).

Also, you may still end up with an object like GameManager, but clearly, it exists at a very high level, and it should concern itself with high level tasks. Maintaining a catalogue of game objects? Perhaps. Facilitating communication between game objects? Sure. Calculating collisions between objects? No! This is also why the name Manager is frowned upon - it's too broad, and allows for much abuse under that banner.

A quick rule of thumb on class sizes: if you are running into several hundred lines of code per class, something is starting to go wrong. Without being overzealous, anything over, say, 300 LOC is a code smell to me, and if you are going over 1000, warning bells should be going off. By believing that somehow that 1000 lines of code is simpler to understand than 4 well structured classes of 250 each, you are deluding yourself.

When time becomes an issue, no way to write a separate class, or to split this giant manager into sub-managers.

I think this is the case only because the problem is allowed to propagate to the point where everything is a complete mess. The practice of refactoring is really what you are looking for - you need to continuously improve the design of the code in tiny increments.

What would you suggest to prevent this from happening?

The problem isn't a technological one, so you shouldn't look for technological fixes for it. The problem is this: there is a tendency in your team to create monolithic pieces of code, and the belief that it's somehow beneficial in the medium / long term to work like this. It also seems that the team is lacking a strong architectural lead, who would steer the architecture of the game (or at least, this person is too busy to perform this task). Basically, the only way out is to have team members recognise that this thinking is wrong. It does nobody favours. The quality of the product will worsen, and the team will only spend even more nights fixing things.

The good news is that the immediate, tangible benefits of writing clean code are so great, that almost all developers realise their benefits very quickly. Convince the team to work this way for a while, the results will do the rest.

The difficult part is that developing a feel for what constitutes bad code (and a talent for quickly coming up with a better design) is one of the more difficult skills to learn in development. My suggestion hinges around the hope that you have someone senior enough in the team who can do this - it is much easier to convince people that way.

Edit - A bit more info:

In general, I don't think your problem is limited to game development. At its core, it's a software engineering problem, hence my comments in that direction. What may be different is the nature of the game development industry, whether its more results and deadline oriented than other types of development, I am not sure.

Specifically for game development though, the accepted answer to this question on StackOverflow regarding "especially game architecture" tips, says:

Follow the Solid principles of object oriented design....

This is essentially exactly what I am saying. When I'm under pressure, I also find myself writing large pieces of code, but I've drilled it into my head that that is technical debt. What tends to work well for me, is to spend the first half (or three-quarters) of the day producing a large amount of medium-quality code, and then to take a sit back, and think about it for a while; do a bit of design in my head, or on paper / whiteboard, about how to improve the code a bit. Often, I notice repetitive code, and am able to actually reduce the total lines of code by breaking things up, all the while improving readability. This time invested pays for itself so quickly, that calling it an "investment" sounds silly - quite often I'll pick up bugs that might have wasted half my day (a week later), had I allowed it to go on. What I am saying is very simply:

  • Fix things on the same day you code them.
  • You will be glad you did within hours.

Coming to actually believe the above is difficult; I've managed to do it for my own work only because I've experienced, over and over again, the effects. Even so, it's still difficult for me to justify fixing up code when I could be churning out more... So I definitely understand where you're coming from. Unfortunately, this advice is perhaps too generic, and not easy to do. I strongly believe in it, however! :)

To answer your specific example:

Uncle Bob's Clean Code does an amazing job of summarising what good quality code is like. I happen to agree with almost all of its contents. So, when I think of your example of a 30 000 LOC manager class, I can't really agree with the "good reason" part. I don't want to sound offensive, but thinking that way will lead to the problem. There is no good reason for having that much code in a single file - it's almost 1000 pages of text! Any benefit of locality (execution speed, or design "simplicity") will immediately be nullified by the developers being completely bogged down trying to navigate that monstrosity, and that's even before we discuss merging, etc.

If you aren't convinced, my best suggestion would be to grab a copy of the above book, and have a look through it. Applying that type of thinking to leads to people voluntarily creating clean, self-explanatory code, which is nicely structured.

\$\endgroup\$
6
  • \$\begingroup\$ This isn't a flaw I've seen once. I've seen this in several teams, for several projects. I've seen many talented, structured people struggling with this. When under pressure the 300 lines of code limit is not something your producer cares about. Nor the player btw. Sure this is nice and sweet, but devil is in the details. The worst case of a GameManager I've seen so far was around 30.000 lines of code, and I'm pretty sure most of it was here for a very good reason. This is extreme of course, but those things happen in the real world. I'm asking for a way to limit this GameManager-effect. \$\endgroup\$ Apr 16, 2012 at 13:24
  • \$\begingroup\$ @lorancou - I've added quite a bit of extra info to the post, it was a bit too much for a comment, hopefully it gives you a bit more of an idea, even if I can't point you to any concrete architectural examples. \$\endgroup\$
    – Daniel B
    Apr 16, 2012 at 13:50
  • \$\begingroup\$ Ah, I didn't read that book so that's definitely a good suggestion. Oh, and I didn't mean that there's a good reason to add code in a thousands-line class. I meant that all the code in that kind of god object does something useful. I probably wrote that a bit too fast ;) \$\endgroup\$ Apr 16, 2012 at 14:04
  • \$\begingroup\$ @lorancou Hehe, that's good... that way lies insanity :) \$\endgroup\$
    – Daniel B
    Apr 16, 2012 at 14:07
  • \$\begingroup\$ "The practice of refactoring is really what you are looking for - you need to continuously improve the design of the code in tiny increments.". I think you've got a very strong point there. Mess attracts mess, that's the real reason behind this, so mess has to be fought on the long term. I'm going to accept this answer, but it doesn't mean there's no value in the others! \$\endgroup\$ Apr 18, 2012 at 19:18
7
\$\begingroup\$

This is not really an issue with game programming, but with programming in general.

all the source code is actually here to manage the game.

This is why you should frown at any Object Oriented coder that'll suggest classes with "Manager" in the name. To be fair, I think it's virtually impossible to avoid "semigod" objects in game, but we just call them "system".

Any software tends to get dirty when the deadline is near. That's part of the job. And there is nothing inherently wrong with "duct type programming", particularly when you must ship your product in a few hours. You can't get rid of this problem totally, you can just reduce it.

Though obviously, if you're tempted to put things in the GameManager, it means that you don't have a very healthy code base. There could be two problem :

  • Your code is too complex. Too many patterns, premature optimisation, nobody understands the flow anymore. Try to use more TDD when developing if you can, for it's a very good solution to fight complexity.

  • Your code is not well structured. You're (ab)using globals variable, the classes are not loosely coupled, there is no interface whatsoever, no event system, and so on.

If the code seems fine, you'll juste have to remember, for each project, "what went wrong" and avoid it next time.

Finally, it could also be a team management issue : was there enough time ? Did everybody know about the architecture you were going for ? Who the hell allowed a commit with a class with the word "Manager" in it ?

\$\endgroup\$
3
  • \$\begingroup\$ There's nothing wrong with duct tape programming, I give you that. But I'm pretty sure -Manager classes are all around in game engines, at least I've seen them a lot. They're useful as long as they don't grow too big... What's wrong with a SceneManager or a NetworkManager? I don't see why we should prevent them, or how replacing -Manager by -System helps. I'm looking for suggestions for a replacement architecture for what usually goes into a GameManager, something less code-bloat-prone. \$\endgroup\$ Apr 16, 2012 at 9:31
  • \$\begingroup\$ What's wrong with a SceneManager ? Well, what's the difference between a Scene and a SceneManager ? A Network and a Network Manager ? On the other aspect : I don't think this is an architecture issue, but if you could give a concrete example of something that is in the GameManager and shoudln't be there, it would be easier to suggest a solution. \$\endgroup\$
    – Raveline
    Apr 16, 2012 at 15:54
  • \$\begingroup\$ OK, so forget about the -Manager thing. Let's say you've got a class that handles your game states, lets call it GameStatesCollection. In the beginnings you'll just have a few game states and ways to switch between them. Then there's the loading screens that come and complicate all this. Then some programmer has to deal with a bug when the user ejects the disc while you switch from Level_A to Level_B, and the only way to fix it without spending half a day refactoring is in GameStatesCollection. Boom, a god object. \$\endgroup\$ Apr 16, 2012 at 16:38
5
\$\begingroup\$

So, bringing one possible solution over from the more Enterprise-y world: have you checked out inversion of control/dependency injection?

Basically, you get this framework that is a container for everything else in your game. It, and only it, knows how to wire everything together and what the relationships are between your objects. None of your objects instantiate anything inside their own constructors. Rather than creating what they need, they ask for what they need from the IoC framework; upon creation, the IoC framework "knows" what object is needed to satisfy the dependency and fills it. Loose coupling FTW.

When your EnemyTreasure class asks the container for a GameLevel object, the framework knows what instance to give it. How does it know? Maybe it instantiated it earlier, maybe it asks some nearby GameLevelFactory. Point is, the EnemyTreasure doesn't know where the GameLevel instance came from. It only knows that its dependency is now satisfied and it can get on with its life.

Oh, I see your PlayerSprite class implements IUpdateable. Well that's great, because the framework automatically subscribes every IUpdateable object to the Timer, which is where the main game loop is. Every Timer::tick() automatically calls all the IUpdatedable::update() methods. Easy, right?

Realistically, you don't need this bighugeohmygod framework to do this for you: you can do the important bits of it yourself. The point is that if you find yourself making -Manager type objects then, chances are, you are not distributing your responsibilities among your classes correctly or are missing some classes somewhere.

\$\endgroup\$
3
  • \$\begingroup\$ Interesting, first time I've heard about IoC. This could be too bighugeohmygod for game programming, but I'll check that out! \$\endgroup\$ Apr 16, 2012 at 9:37
  • \$\begingroup\$ IoC, Didn't we just use to call it common sense? \$\endgroup\$
    – brice
    Apr 16, 2012 at 22:25
  • \$\begingroup\$ Given half a chance, an engineer's gonna make a framework out of anything. ( = Besides, I'm not advocating using the framework, I'm advocating the architectural pattern. \$\endgroup\$
    – drhayes
    Apr 16, 2012 at 23:16
2
\$\begingroup\$

In the past, I generally end up with a god class if I do the following:

  • sit down at the game editor/IDE/notepad before I've written out a class diagram (or just a sketch of the main objects)
  • Start with an very vague idea of the game and immediately code it, then start iterating on new ideas as they come
  • create a class file called GameManager when I'm not making a statebased game like a turn based strategy where GameManager is actually a domain object
  • don't care about code organization early on

This may be controversial, which I'll laugh if it is, but I can't think of a single time even in prototyping that you shouldn't write a very basic class diagram before writing a playable prototype. I do tend to test tech ideas before planning, but that's about it. So if I wanted to make portal, I would write very basic code to get the portals working, then say ok great time for some minor planning then I can work on the playable prototype.

\$\endgroup\$
1
\$\begingroup\$

I know this question is old now, but I thought I'd add my 2 cents.

When designing games, I nearly always have a Game object. However, it is very high level and doesn't really "do anything" itself.

For example, it tells the Graphics class to Render, but has nothing to do with the rendering process. It might ask the LevelManager to load a new level, but has nothing to do with the loading process.

In short, I use a semi-godlike object to orchestrate the use of the other classes.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ This isn't very god-like at all - this is called abstraction. :) \$\endgroup\$ Jul 8, 2013 at 12:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .