You already used the Game class in the previous chapters, but other than starting the game by calling the Run method from the Program class and your unit tests and using the Initialize, Update, and Draw methods, those chapters did not talk about the underlying design. Well, you don’t really need to know anything else if you are just creating a few simple games, but as games become bigger and have more features you might want to think about the class overview and class design of your game.
The Game class itself is used to hold the graphics device in the GraphicsDeviceManager instance and the content manager in the content field. From the Program class you just have to create an instance of your game class and call the Run method to get everything started. Unlike in the old days with Managed DirectX or OpenGL you don’t have to manage your own window, create your game loop, handle Windows messages, and so on. XNA does all that for you, and because it is handled in such a way it is even possible to run your game on the Xbox 360 platform where no window classes or Windows events are available.
It is still possible to access the window of the game through the Window property of the game class. It can be used to set the window’s title, specify if the user is allowed to resize the window, get the under lying Windows handle for interop calls, and so on. All these methods do nothing on the Xbox 360 platform. There is no window, there is no window title, and it can certainly not be resized. As you already saw in the previous game, you used the Window.Title property to set some simple text to the title for showing the current level and score to the user. The reason you did that is because there is no font support in XNA; to render text on the screen you have to create your own bitmap font and then render every letter yourself. In the next games and even for the Tetris game you will need that feature, and therefore the TextureFont class is introduced in a few minutes.
Additionally, it is worth mentioning that it is possible to set the preferred resolution in the game class constructor by setting the graphics properties like in the following example, which tries to use the 1024×768 resolution in fullscreen mode:
graphics.PreferredBackBufferWidth = 1024; graphics.PreferredBackBufferHeight = 768; graphics.IsFullScreen = true;
There is no guarantee that the game will actually run in that mode; for example, setting 1600×1200 on a system that just supports up to 1024×768 will only use the maximum available resolution.
You already know that Update and Draw are called every frame, but how do you incorporate new game components without overloading the game class itself? It’s time to look at the game classes and components overview of the Tetris clone game (see Figure 4-1).
The first thing you will notice is that you have now three game classes instead of just one like in the previous game examples. The reason for that is to make the main game class shorter and simpler. The BaseGame class holds the graphics manager with the graphics device, the content manager, and it stores the current width and height values of the current resolution you use in the game. The Update and Draw methods also handle the new Input, Sound, and TextureFont classes to avoid having to update them in the main game class. Then the TetrisGame class is used to load all the graphics from the content pipeline and initialize all sprites and game components, which you learn about in a second.
Finally, the TestGame class derives itself from the TetrisGame class to have access to all the textures, sprites, and game components, and it is only used in debug mode to start unit tests. The functionality of the TestGame class is very similar to the previous chapters, but this time it is organized in a nice way and separate from your main game class. The TetrisGame class uses several unit tests to make sure each part of the game works as you have planned.