What Is a Game Loop?
This overview covers the following topics.
- Making a New Game
- Game Loop Timing
- Game Components
- Game Services
- Game Components Consuming Game Services
Making a New Game
The first step in creating a new game is to make a class that derives from Game. The new class needs to override Update, Draw, and Initialize. The Update method is responsible for handling game logic, and the Draw method is responsible for drawing each frame. The Initialize method is responsible for game setup before the first frame of the game.
Game Loop Timing
A Game is either fixed step or variable step, defaulting to fixed step. The type of step determines how often Update will be called and affects how you need to represent time-based procedures such as movement and animation.
Fixed-Step Game Loops
A fixed-step Game tries to call its Update method on the fixed interval specified in TargetElapsedTime. Setting Game.IsFixedTimeStep to true causes a Game to use a fixed-step game loop. A new XNA project uses a fixed-step game loop with a default TargetElapsedTime of 1/60th of a second.
In a fixed-step game loop, Game calls Update once the TargetElapsedTime has elapsed. After Update is called, if it is not time to call Update again, Game calls Draw. After Draw is called, if it is not time to call Update again, Game idles until it is time to call Update.
If Update takes too long to process, Game sets IsRunningSlowly to true and calls Update again, without calling Draw in between. When an update runs longer than the TargetElapsedTime, Game responds by calling Update extra times and dropping the frames associated with those updates to catch up. This ensures that Update will have been called the expected number of times when the game loop catches up from a slowdown. You can check the value of IsRunningSlowly in your Update if you want to detect dropped frames and shorten your Update processing to compensate. You can reset the elapsed times by calling ResetElapsedTime.
Variable-Step Game Loops
A variable-step game calls its Update and Draw methods in a continuous loop without regard to the TargetElapsedTime. Setting Game.IsFixedTimeStep to false causes a Game to use a variable-step game loop.
Animation and Timing
For operations that require precise timing, such as animation, the type of game loop your game uses (fixed-step or variable-step) is important.
Using a fixed step allows game logic to use the TargetElapsedTime as its basic unit of time and assume that Update will be called at that interval. Using a variable step requires the game logic and animation code to be based on ElapsedGameTime to ensure smooth gameplay. Because the Update method is called immediately after the previous frame is drawn, the time between calls to Update can vary. Without taking the time between calls into account, the game would seem to speed up and slow down. The time elapsed between calls to the Update method is available in the Update method's gameTime parameter. You can reset the elapsed times by calling ResetElapsedTime.
When using a variable-step game loop, you should express rates—such as the distance a sprite moves—in game units per millisecond (ms). The amount a sprite moves in any given update can then be calculated as the rate of the sprite times the elapsed time. Using this approach to calculate the distance the sprite moved ensures that the sprite will move consistently if the speed of the game or computer varies.
Game components provide a modular way of adding functionality to a game. You create a game component by deriving the new component either from the GameComponent class, or, if the component loads and draws graphics content, from the DrawableGameComponent class. You then add game logic and rendering code to the game component by overriding GameComponent.Update,DrawableGameComponent.Draw and GameComponent.Initialize. A game component is registered with a game by passing the component to Game.Components.Add. A registered component will have its draw, update, and initialize methods called from the Game.Initialize, Game.Update, and Game.Draw methods.
Game services are a mechanism for maintaining loose coupling between objects that need to interact with each other. Services work through a mediator—in this case, Game.Services. Service providers register with Game.Services, and service consumers request services from Game.Services. This arrangement allows an object that requires a service to request the service without knowing the name of the service provider.
Game services are defined by an interface. A class specifies the services it provides by implementing interfaces and registering the services with Game.Services. A service is registered by calling Game.Services.AddService specifying the type of service being implemented and a reference to the object providing the service. For example, to register an object that provides a service represented by the interface IMyService, you would use the following code.
Services.AddService( typeof( IMyService ), myobject );
Once a service is registered, the object providing the service can be retrieved by Game.Services.GetService and specifying the desired service. For example, to retrieve IGraphicsDeviceService, you would use the following code.
IGraphicsDeviceService graphicsservice = (IGraphicsDeviceService)Services.GetService( typeof(IGraphicsDeviceService) );
Game Components Consuming Game Services
The GameComponent class provides the Game property so a GameComponent can determine what Game it is attached to. With the Game property, a GameComponent can call Game.Services.GetService to find a provider of a particular service. For example, a GameComponent would find the IGraphicsDeviceService provider by using the following code.
IGraphicsDeviceService graphicsservice = (IGraphicsDeviceService)Game.Services.GetService( typeof( IGraphicsDeviceService ) );