Game Architecture Day 2

Logo of the XNA Game Game Architecture tutorial series, three interlocked gears

Stylish logo of two engaged gears with the text XNA Game Architecture

Welcome to day 2 of the XNA Game Architecture series!

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 ;)!

Modularization

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

UML diagram of a huge Game class with dozens of members

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:

UML diagram of a lean Game class encircled by several other classes

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! 😉

Encapsulation

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:

UML diagram of a DVD burning application with IOCTLs in the Form classes

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:

class DvdWriter {
  public DvdDrive[] GetDrives();
  public void WriteIso(DvdDrive drive, string isoPath);
  public void VerifyDvd(DvdDrive drive);
}

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.

UML diagram of a DVD burning application with IOCTL logic in a separate class

  • 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.

Abstraction

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:

UML diagram showing a particle system class directly accessing the graphics device

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:

UML diagram showing the particle system accessing the graphics device through an interface

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.

Next Chapter

In the next chapter, I will finally start writing some code and explain the concept of Dependency Injection and how to wire up a game’s classes with each other using an Inversion of Control container.

3 Responses to “Game Architecture Day 2”

  1. stefan says:

    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.

    Thank you

  2. Cygon says:

    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).

  3. stefan says:

    That’s a bummer, the XNA community could really use more articles/series like This one.

    Thank you for the wonderful content on this site!

Leave a Reply

Your email address will not be published. Required fields are marked *

Please copy the string dSPnSp to the field below: