In the previous tutorial, we took a look at the game loop. This pattern is incredibly versatile, and nearly every game uses some form of it. In this tutorial, we'll dig into it a little bit more, and look at the GameTime object that we're given in every call to Update or Draw. This class gives us insight into what's going on in the game loop. In a sense, this is like the game's heart beat, pulsing many times a second, driving your game forward.
In this tutorial, we'll focus solely on understanding the GameTime class, as well as the TimeSpan class that it uses. In the upcoming tutorials, we'll look at how to configure the game loop to our liking.
In previous tutorials, we've generally ignored the gameTime parameter. We've assumed (correctly, for the most part) that each frame (cycle through the game loop) will take the same amount of time. By default, XNA will regulate the game loop to try to enforce this, and it is able to do so, as long as the game isn't running slowly. But knowing how to use the GameTime object that we're given will be an important step in managing the frame rate of the game loop, which we'll cover in more depth in the next tutorial.
By default, XNA will try to maintain a frame rate of 60 frames per second, making each frame take 0.0166667 seconds. Again, in the next tutorial, we'll look at how to configure this yourself, but for now, our focus is on understanding the GameTime object.
Breaking Down the GameTime Class
If you look at your Update method and Draw method, you will see that you've been given an instance of the GameTime class in both cases. The GameTime class gives you three properties of interest: TotalGameTime, ElapsedGameTime, and IsRunningSlowly.
Both TotalGameTime and ElapsedGameTime are object of type TimeSpan, which is actually a part of the Base Class Library. It isn't unique to XNA. You can use it in any C# application. These two contain all of the interesting timing information that you may want to know about. We'll break down TimeSpan objects in a second.
TotalGameTime tells you how long your game has been running for since it was started. This continues to run until the player quits the game. ElapsedGameTime, on the other hand, tells you how long it has been since the last Update or Draw (depending on if it is in Update or Draw). In theory, this is how long a complete cycle through the game loop has taken. Interestingly, there's a couple of gotchas with this, but that's a topic for an upcoming tutorial, not for right now.
For the moment, we'll assume that your game is running fast enough that there are no delays, and that ElapsedGameTime reflects how long it has been since the last update.
Speaking of running slowly, the third property of GameTime, IsRunningSlowly, is a boolean value indicating whether the game is running slower that it was told to run. It's kind of crazy, but even if IsRunningSlowly is true, and the game is running slowly, you won't necessarily see ElapsedGameTime slow down. This is a little perplexing, but stick with me for a couple more tutorials, and I'll explain why.
Breaking Down the TimeSpan Struct
Both TotalGameTime and ElapsedGameTime are instances of the TimeSpan struct. This type gives you a couple of ways of accessing the timing information it contains, and it is important to understand these two distinctions.
If you look at the properties that TimeSpan provides, you'll see two matching sets of properties: Days, Hours, Minutes, Seconds, and Milliseconds, as well as TotalDays, TotalHours, TotalMinutes, TotalSeconds, and TotalMilliseconds.
These properties that start with Total, combined with the word Total in TotalGameTime, is what leads to confusion in knowing what variables to use. So it's important to keep the two separated in your mind. Always remember: GameTime has TotalGameTime and ElapsedGameTime, both of which have their own set of properties that start with Total, and a set that does not.
Now going back to these two sets, let's take a minute and describe what the difference between the set that starts with Total, and the set that does not. To help explain the differences, let's say that you have a TimeSpan object that represents a time span of 2 minutes and 17.3 seconds. (Which could be a total game time or just an elapsed game time. It doesn't matter at this point.)
Days, Hours, Minutes, Seconds, and Milliseconds are designed to be used together, to represent the whole time. For this time span, Days and Hours would have a value of 0, Minutes would have a value of 2, Seconds would have a value of 17, and Milliseconds would have a value of 300.
On the other hand, the set that begins with Total represent the total length of the time span in whatever unit you choose. So TotalDays will be 0.001589, since that time span is equal to that many total days, TotalHours will be 0.038138, TotalMinutes will be 2.28833, TotalSeconds will be 137.3, and TotalMilliseconds will be 137300.
So here's the key. Generally speaking, you'll use the set without Total to build timing information that you want to show to the user, while the ones with Total are used to do actual calculations for your game. And you'll use TotalGameTime when you're interested in the overall running time of the game, and ElapsedGameTime when you're interested in how long it has been since the last update.
When all is said and done, in a real game, you'll use gameTime.ElapsedGameTime.Seconds frequently (or gameTime.ElapsedGameTime.Minutes, etc.) and gameTime.TotalGameTime or gameTime.ElapsedGameTime.Seconds very rarely.
Now that we know how the GameTime and TimeSpan classes function, we're ready to talk about how you can control the waiting stage of the game loop with a discussion on time steps, and we'll follow that up with a look at a confusing time related situation that often arises for people as they're making XNA games.
|Having problems with this tutorial? Try the troubleshooting page!|