Game.GameServices

Game.GameServices

I was originally going to create a tutorial that walks you through creating a custom GameComponent, perhaps the Framerate component from my demo or an event driven Keyboard component, but I’ve actually seen several of these pop up over the last few days so perhaps you’ve got the hang of it. J

What I have seen are a few questions about are game services and particularly IGraphicsDeviceService. So I thought I’d write up a quick description of game services as well as the proper way to query and use the IGraphicsDeviceService.

GameServices

A game service can be thought of as a service that is available to anyone that has a reference to a Game. The idea behind it was there are certain types, or services, that a component should be able to depend on for its functionality. If that service isn’t available, then the component can’t operate correctly. The first one we thought of (and one of the reasons behind introducing services) was making a GraphicsDevice reference available across a game. Originally we had the Game own the GraphicsDevice and expose it via a property like Game.GraphicsDevice. The problem with this was that this tightly bound the GraphicsDevice to the Game, not allowing someone else to “own” the device (such as a renderer) and preventing someone from using a future updated GraphicsDevice without shipping a new version of Game that wouldn’t be backwards compatible. So to achieve the loose coupling of a GraphicsDevice and a Game, we factored the device management and ownership into a GameComponent, which is how GraphicsComponent came to be. We still needed to make the GraphicsDevice available across a Game or even outside of the Game. As long as someone has a reference to a Game, they should be able to get a hold of a GraphicsDevice, if it’s available. That’s the idea behind a game service. The GraphicsComponent “publishes” an interface, IGraphicsDeviceService, as a service that others can query for and obtain a reference to. In this sense, a service is a singleton that is keyed off the type of the service itself. So a component that needs to render using a GraphicsDevice, doesn’t have to be tied to a GraphicsComponent, it can just query for the IGraphicsDeviceService instead. Imagine if someone wanted to create a high-level renderer that owned the GraphicsDevice itself, rather than use the GraphicsComponent. They could create the renderer as a GameComponent and publish an instance of the IGraphicsDeviceService themselves and now the Game has use of a new renderer and all game components that depended on a GraphicsDevice will still work too!

One other benefit of services is that Game.GameServices can be passed to the ContentManager so the type loaders in the content manager can query for services (this is how textures load for instance). Because the container is passed one can add additional content types to the content manager (via a custom type loader) that relies on a custom game service without any intervention on our part.

So that was a quick explanation of a game service (complete with a GraphicsComponent history!) but it should help convey what the purpose of a service is and when you’d use them. They really are meant to be a system wide service that something can query for.

IGraphicsDeviceService

As mentioned above, game components that wish to render something on the screen need to get a reference to a GraphicsDevice. They could expose a property that is of type GraphicsComponent, but this would cause them to not work if a Game used something else to manage the GraphicsDevice, such as a custom renderer. Instead a GameComponent that wishes to make use of the GraphicsDevice should query for the IGraphicsDeviceService from Game with the following line of code:

// The event that occurs when a graphics device is in the process of resetting.

eventEventHandler DeviceResetting;

}

As you can see the interface provides a reference to the GraphicsDevice as well as several events that you should use to properly detect when you need to load and unload your graphic resources such as textures, vertex buffers, index buffers and effects. It’s also important to note that you should only cache a reference to the interface, not a reference to the GraphicsDevice. This is because the reference to the GraphicsDevice can (and most likely will) change over the course of a Game due to window resizing, changing monitors, etc. The reference to the service, however, will remain the same throughout the game.

So you should typically query for the service and hook up the events you care about inside of the Start method of a GameComponent like so:

So I hope this was a helpful explanation of what game services are, why they are important and also what the IGraphicsDeviceService is for and how to use it. Please let us know what you think over at the XNA Framework forum.