In this post I want to build on the Game Components that I discussed previously. At the end of my last posting we were left with a DrawableGameComponent, which had its Draw method being called automatically by the main game object. To draw a mesh in this method, however, we’re going to need to know the view & projection matrices to transform our mesh with. These will typically be shared with the other objects we will be rendering and probably ‘owned’ by some sort of camera class. Ideally we want our camera & drawable objects to be entirely decoupled from one another, so that they can be modified, removed or replaced in isolation.
The GameServicesContainer
Once again the solution to this problem can be found in the default game class. It has a property called Services that is an implementation of a GameServiceContainer which can manage the functionality offered by one component to another:
In our example, the camera component can offer the drawable components a view & projection matrix for rendering themselves during their Draw methods.
Creating Camera & Input Interfaces
To begin we start by defining an interface that all of our subsequent camera types will offer:
interface ICameraService
{
Matrix View{get;}
Matrix Projection{get;}
}
While we’re at it we can define an abstracted input interface to move the camera around under user control. I find that I often want to create a control system that will accept either gamepad or keyboard input. One way I have achieved this is to abstract the intent of the player from the actual method by which the player indicates their intent. The camera needs to know that the player intends to ‘turn left’ or ‘move right’, but it doesn’t need to know if, to achieve this, they are pressing the left arrow key on the keyboard, moving the left stick of a gamepad or even moving the mouse. So the interface we will use in this example is as follows:
interface IInputService
{
float LookX();
float LookY();
float MoveX();
float MoveY();
float MoveZ();
}
If at a later stage we want to want to change the source of these actions it will be nicely decoupled from the other objects in our game.
Now that we have defined the information our components are going to exchange via these interfaces, we need to create some objects that actually implement them.
Structure
For the purposes of this discussion, we’re going to create 3 classes, all derived from the GameComponent class I talked about in my last posting. The class holding the mesh we are going to render is derived from the DrawableGameComponent subclass. The two other component classes also each offer the interfaces outlined above. These interfaces define the services that these components will offer the other components in our game. In summary then the class structure of the project will look like this:

The 3D model, input mediation and camera are all dealt with using Game Components, which only communicate with other via the services that they provide or receive through the Game Services container in the main game object (as described above). This makes it easy to maintain or modify our code as the project grows, as there are no direct dependencies between any of these elements.
Providing A Service
The first object in the demo project we will look at is the ControlComponent. This simply checks the keyboard or player one controller during its Update method and then offers look or move values via its implementation of the methods from the IInputService interface. Since it is derived from a GameComponent class, it has a Game property that gives us access to its parent game object (in my previous posting I highlighted that a reference to the parent game object is required during a GameComponent’s construction). Using the Game property of the component we can have it register the service it is offering with the game’s Service Container during initialization thus:
public override void Initialize()
{
Game.Services.AddService(typeof(IInputService), this);
base.Initialize();
}
The game’s service container now knows that it can offer the methods defined in an IInputService interface to any components that require them. In our case this will be the camera object.
Requesting a Service
If you take a look at the CameraComponent class in my demo project you will see that, in addition to adding its own ICameraService to the game’s Service Container, it also requests an IInputService. For consistency I’ve also had the object access the graphics device via an interface & service. This is another service already offered by the framework by default. The Inialize function for the CameraComponent is, therefore:
public override void Initialize()
{
// Add our own service to the Game Service container
Game.Services.AddService(typeof(ICameraService), this);
// Get back the services we require
IGraphicsDeviceService graphicsservice = (IGraphicsDeviceService)Game.Services.GetService(typeof(IGraphicsDeviceService));
m_input = (IInputService)Game.Services.GetService(typeof(IInputService));
m_aspectRatio = (float)graphicsservice.GraphicsDevice.Viewport.Width /
(float)graphicsservice.GraphicsDevice.Viewport.Height;
base.Initialize();
}
So we have something (mildly) interesting to look at, I have implemented the simple ModelDrawableComponent class that requests a view & projection matrix via the ICameraService, which it then uses to update its internal matrices and use in its Draw method. The two key functions worth highlighting here are:
public override void Update(GameTime gameTime)
{
if (m_camera != null)
{
m_projectionMatrix = m_camera.Projection;
m_viewMatrix = m_camera.View;
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
// Copy any parent transforms.
Matrix[] transforms = new Matrix[m_model.Bones.Count];
m_model.CopyAbsoluteBoneTransformsTo(transforms);
GraphicsDevice.RenderState.DepthBufferEnable = true;
// Draw the model. A model can have multiple meshes, so loop.
foreach (ModelMesh mesh in m_model.Meshes)
{
// This is where the mesh orientation is set, as well as our camera and projection.
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = transforms[mesh.ParentBone.Index] * m_rotationMatrix * m_translationMatrix;
effect.View = m_viewMatrix;
effect.Projection = m_projectionMatrix;
}
// Draw the mesh, using the effects set above.
mesh.Draw();
}
base.Draw(gameTime);
}
During inialization the component has asked for an ICameraService m_camera. If we successfully receive a reference to this (it is not null) then we can use it get the camera’s matrices for transformation.
Linking it all together
Finally, we just need to wire everything up. As has already been mentioned, the individual components know nothing about one another, so all of this wiring occurs in the game object. First I add the ControlComponent that makes its IInputService available via the game object's Services property. Next I add the CameraComponent that requests this service and offers its own ICameraService into the mix. Finally I add the ModelDrawableComponent that uses the ICameraService to draw itself.
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
Components.Add(new Components.ControlComponent(this));
Components.Add(new Components.CameraComponent(this));
Components.Add(new Components.ModelDrawableComponent(this));
}
That's it! No more code needs to sneak into the game object for us to render a 3D model that we can move around using either the keyboard arrow keys, or the player one gamepad. Crucially, if we need to change the way the movement of the camera should behave, modify the model, change the input controls or add more objects to our scene they can all be dealt with in isolation without affecting other parts of our project. It is very handy to build a library of useful components that you can 'drop in' trivially to new projects immediately from the start - a frame counter, origin indicator, scale grid and text boxes are all the sort of components I'm sure most people need time and time again.

I’m sure that this discussion will be rather basic for many visitors to this site. It is also worth pointing out the obvious performance overhead in overdoing it on the component front. Rather than making all of your objects individual DrawableComponents, you will more likely want to limit them to higher level object managers or a scene graph. However, I do hope this posting is useful to some people and that the design pattern of components & services, especially if it is new to you, is worth going over in the context of the XNA framework. Let me know your thoughts…
Posted
Sun, Aug 23 2009 11:06 PM
by
VeraShackle