Time can be a surprisingly slippery concept to get to grips with. Back when I was working on Allegro it caused the most common question from new programmers, and even though XNA does more than Allegro to handle time for you, it appears some people are still confused. Hopefully this post will clarify how time works in the XNA Framework.
By default XNA runs in fixed timestep mode, with a TargetElapsedTime of 60 frames per second. This provides a simple guarantee:
Digging into exactly what that means, you will realize there are several possible scenarios depending on how long your Update and Draw methods take to execute.
The simplest situation is that the total time you spend in Update + Draw is exactly 1/60 of a second. In this case we will call Update, then call Draw, then look at the clock and notice it is time for another Update, then Draw, and so on. Simple!
What if your Update + Draw takes less than 1/60 of a second? Also simple. Here we call Update, then call Draw, then look at the clock, notice we have some time left over, so wait around twiddling our thumbs until it is time to call Update again.
What if Update + Draw takes longer than 1/60 of a second? This is where things get complicated. There are many reasons why this could happen:
We do the same thing in response to all four causes of slowness:
If you think about how this algorithm deals with the four possible causes of slowdown I listed above, you'll see it handles them all rather well:
In summary, you don't need to do anything special to take advantage of our our fixed timestep logic. Just make sure you put all your game logic inside the Update method (not in Draw!) and everything will run at a nice constant speed.
For bonus points you can automatically adjust your game detail in response to the IsRunningSlowly flag, but most games are fine not bothering with this.
If you put breakpoints on your Update and Draw methods you may notice us calling Update more often than Draw, but this is just because the breakpoint has made us late and we are trying to catch up. Timing is a great example of the Heisenberg Uncertainty Principle: by examining the way the timing system is behaving, you change the timings, and get different results than when you let the game run normally.
You can change the TargetElapsedTime property if you want to run a fixed timestep game at something other than 60 frames per second. We chose that default because it matches the standard television refresh rate, but some games might want to slow this down to 30 frames per second.
If you disable fixed timesteps, XNA does nothing clever for you. Our algorithm in this mode is extremely simple:
(that is actually a slight simplification, but the details are unimportant)
There are some significant advantages to running in this mode:
The downside is that variable timestep games are much harder to program. Even simple computations such as "add velocity to position" must be adapted to take the elapsed time into account. For anything more than the most trivial calculations this requires you to integrate the equation, so you can evaluate how it changes over a period of time. Some people are good at calculus, but I'm not, and I don't much enjoy having to deal with such things every time I want to move a game object!
So, which mode is better? Game programmers have argued about this since the dawn of time, and will probably still be arguing when the universe implodes around us.
As a rule of thumb, console programmers prefer fixed timesteps, while PC programmers usually go for variable timing mode. There are two main reasons for this disparity:
But there are no absolute rules. I've seen console games that worked well using variable timesteps, and I personally shipped a PC title that ran just fine with a 60 fps fixed timestep.
XNA defaults to fixed timestep mode because that is easier to program, but you are welcome to change this if you disagree with our choice.
There is no law saying all parts of a game must update at the same frequency. For instance MotoGP combined three different update rates:
Running some parts of your update logic less often than others is a great way to make games more efficient. For instance pathfinding and AI often only need to be updated a couple of times a second. Once you have found a good path or made the decision to attack, you can follow that decision without having to repeat the entire original calculation on each update.