Game Architecture Day 2

I have thought hard about whether I should just assume a certain level of object
oriented programming knowledge in this series. People picking up these articles likely
already have some knowledge about objects and design, so I settled on a quick
run-over of the principles that hopefully won’t bore the seasoned developers and
provide a good reference for people just starting out!

If you already know all this, feel free to skip ahead until it becomes interesting
again or to the next chapter ;)!

Many programmers using XNA to learn programming end up with something like this:

That’s quite okay for someone doing his first steps, but obviously, as the code
grows larger, this kind of design becomes pretty hard to maintain and it will be
increasingly difficult to remember what all those fields are there for and where
the code for doing something needs to go.

No programmer is capable of keeping every method and every field of even a
moderately sized game in his head at once, so we break the problem down into
small parts that we can understand – using methods and classes. It’s a bit more
work to write those classes and to wire them up to each other, but if we do our
job well, the project is much easier to maintain and we have more fun working
on it, too!

Here’s what might become of above class with some modularity applied:

Knowing what to turn into classes and how to make them interact with each
other comes with experience. And hopefully, by the end of this series, you will
have a bit more of that! 😉

As the game grows, the number of classes will also grow until there are too
many of them interacting with each other to keep track of. So classes alone
are not the final solution to keeping a game’s code base manageable.

One method of combatting this complexity is to limit the amount of members
exposed by a class. This is best illustrated with an example: Imagine you were
writing a DVD burning application. At some point, you will have to delve into
the gory details of the some obscure API used to control the DVD drive.

One could sprinkle bits of this code all over the application. The drive selection
dialog would contain some code that looks at what DVD drives are available,
the burn dialog would contain some code that sends the data to be burned to
the DVD drive bit by bit, and so on — like this:

But this makes it hard to keep track of what’s going on. Worse even, if you later
port that application, say from WinForms to WPF, you have to isolate all those
pieces of code from its dialogs and re-add them to the WPF code. And if you decide
to also create a command-line version of the application, oh well…

Instead of spreading the DVD drive control code everywhere, you can
encapsulate all that complicated stuff behind a small class:

There might be a lot going on behind those three methods, there might even
be multiple classes involved – the point is, from the outside (meaning the rest of
the application), only those three methods are visible.

When modifying the DvdWriter class, you only need to be
concerned with doing what the three methods promise to do. You can
completely eradicate the rest of the application’s code from your mind.

Vice versa, when working on other parts of the application, you don’t have
to remember the details of how the DVD drive control code works. There are
three simple methods to call and their names reveal exactly what they do.

Of course, the art lies in finding appropriate places where the interactions
between classes can be trimmed down to just a few methods. This, too,
is a matter of experience. Good programmers intentionally design towards
making it possible to build self-contained, encapsulated classes. One trick is
to look for where the concerns change: the dialog is concerned
with managing the user interface, the DVD drive control code is concerned
with burning data to a DVD – thus, these two don’t belong together.

Quite often, classes have to interact with each other. As an example, one
class might manage your particle systems,
another might manage
your graphics device (like XNA’s
GraphicsDeviceManager class ;). That particle system manager needs
to access the graphics device to render its particle systems. But you don’t want
to let the classes directly access each other, otherwise you’d end up with this:

Where is the problem with that?

By directly accessing the GraphicsDeviceManager, the
ParticleSystemManager would become dependent upon this very
class. Should you later decide to create a particle system editor in WinForms which
doesn’t use the GraphicsDeviceManager, you would have
to rewrite a lot of code to get it working.

The ParticleSystemManager has access to everything the
GraphicsDeviceManager provides. Does it make sense that the
ParticleSystemManager is theoretically able to toggle between
full screen and windowed mode?

This concern might not seem terribly obvious (after all, the .NET Framework gives
any part of your program access to lots of silly things it wouldn’t want to do),
but the idea is that exposing only what’s needed makes it easier to change used
classes or to change or replace them.

What you need then is an interface for the GraphicsDeviceManager.
One that lets other classes access only those parts they’re supposed to use.

Luckily, the XNA Framework provides just such an interface. It’s called
IGraphicsDeviceService and the
GraphicsDeviceManager implements it. So instead of directly
accessing the GraphicsDeviceManager, you can do this:

Now the ParticleSystemManager will accept any class
that implements the IGraphicsDeviceService interface. If you
decided to write aforementioned particle system editor, you could implement
IGraphicsDeviceService in a Control or
Form and the ParticleSystemManager could work
with it – without changing a single line of code.

3 Responses to “Game Architecture Day 2”

Hi, i really find this article useful, or at least i think i will because i cant seem to find the follow up article to this? If you did complete the series, please direct me to all the episodes.. i am currently doing my honours degree in information technology and for my research project i would like to research different techniques used for communication between game objects.

I was suffering a serious burnout at the beginning of 2010 and have not continued this series, sorry.

What I was going to teach here (and still think is the right way) was to build the major subsystems (game state manager, GUI root, input device manager, etc.) as a component based architecture where they are only accessed by interface (allowing unit tests to isolate components by mocking the interfaces through which they communicate with the environment). All of those subsystems would then be created through an Inversion of Control container (my preferred choice for .NET: Ninject), ensuring the initialization and termination order is handled automatically and adding dependencies to other components doesn’t require any code changes besides adding an argument to a component’s constructor.

I have a link to a very tidy example application built that way in the comments of this post:Components and Services (the actual article above those comments shows Components and Services as implemented in XNA, which I wouldn’t use at all for projects with a moderate to large scope)

If by “communication between game objects” you mean in-game entities (enemies, switches, bullets, …) notifying each other about collisions, damage, sounds that need to be played, etc. – that is a topic I never wrote anything about because I don’t feel knowledgeable enough about that yet. I only know I strongly, strongly dislike message-passing systems and would for smaller games try a world object model (made-up term; basically model the world with classes and write presenters that maintain representations of those objects in a scene graph) and for larger games use a component entity system such as Artemis or the one implemented in Unity (the 3D authoring kit, not Microsoft’s IoC container).