2015/08/09

Keeping Time with a Game Clock

So, I'm currently in the process of implementing tile maps, which is coming along nicely, but when turned to take care of animations, I realized I hadn't yet come back to talk about timing, and why it's been lacking from my code so far (excluding the Profiler, of course).

Keeping Time: Now

The way MonoGame and XNA provide timing information is with the gameTime parameter of the Game class's Draw and Update methods. Its type is the aptly named class GameTime, which has two TimeSpan properties for the total time since the initial call to Game.Run and the time since the last call to Update, and an IsRunningSlowly flag to help you optimize in certain scenarios.

The way I learned it, you're expected to pass that around all code that requires timing information. Which can be anywhere from half to almost all of your code base.
That alone is a bit annoying, and reason enough to look into alternatives. Just looking at the source code of the Game class tells us that the _gameTime field is never reassigned after initialization, and its initialization is the only construction of a new GameTime instance.
Therefore it stands to reason you could just keep a reference to that very gameTime around wherever you need it, instead of passing it in every frame. Problem is, at least with our major engine subsystems, initialization should be over by the time the first update rolls around.

Keeping Time: From Here On

To fix that I propose a GameClock class. If we manage instantiating that ourselves, we can be certain keeping references to it is save, rather than guessing as with GameTime. We can also initialize it first, so our subsystems can safely complete initialization, without having to wait for the first frame.

The other thing I envision it doing is better medium awareness: There's more to keeping time than frame deltas and the total running time of the game. The latter in particular has literally never been useful to me. I can see passing it to the Steam API at the end of the session, so Steam could track the total amount of playtime with the game, including idle time. Still, it's a little early to be thinking about Steam, wouldn't you say?
What we should be thinking about is relativity. The game may have been displaying the title screen for a while, but when the player finally hits New Game, we should start counting from 0:00. If they load an 8 hour save file, however, we should start from 8:00. We'll call this play time, as opposed to the 15 minute session time.
Finally, the game world may run at an entirely different time scale. If the player picked up a slow down power up, it might run at half speed, or zero speed, when the game is paused (The latter could also be true for play time, when in debug mode).

If you're confident in your engine's determinism, you could also enable frame skipping, and have a mocked out GameClock and InputMapper play back recorded date. This way, you could have hours of playtime run trhough in minutes, which makes for awesome regression tests and might help your QA efforts a lot if you can't afford your own team for that.
I don't have plans to do anything like that at the moment, but it's a nice idea to keep in mind.

Anyway, here's my implementation of such a clock:

No comments:

Post a Comment