Tuesday, March 6, 2012

The Game Module: Loop

The loop module is simple architecturally. It is nestled in the game namespace, and it contains one publicly exposed function, initLoop. It is perhaps the most fundamental component of the game module.

The loop module provides the mechanism necessary to execute a game loop at a specified frames per second. The function initLoop takes two arguments, a step function and an optional fps. The step function advances the game state forward. It is passed a single argument, the time elapsed from the start of the previous frame to the start of the current frame. The game logic implemented in the step function should use the elapsed time to move the game forward. It ensures that the game advances at a consistent pace by basing the degree of advancement on an objective measurement, time. Basing it instead on the number of executions of the loop could be problematic since slower machines may execute the loop at a different pace than a faster machine, and the loop would be executed at a different pace if the developer chose to use a different frame rate. 


The algorithm for implementing the game loop is simple in concept, but the actual implementation is messy since it requires a lot of value juggling among variables. A high level description follows:


Given step function S and frame rate FPS,

  1. Obtain the current time Ti.
  2. Subtract Ti from the time when the last frame began execution, Tpi, to get the elapsed time, deltaT. If this is the first frame execution, deltaT = 0 since Tpi is undefined. 
  3. Run S with input deltaT.
  4. Subtract the current time from Ti to obtain the run time of S, deltaTS. 
  5. Subtract deltaTS from the desired frame period, 1/FPS (the period is the inverse of the frame rate), to obtain the time until the next frame should run, Tw. 
  6. Wait Tw seconds. If Tw <= 0, wait a small default time period.
  7. Set Tpi to Ti.
  8. Perform steps 1 through 8. 
The algorithm assumes each time variable is in seconds. In practice, Javascript returns time in milliseconds, and conversions must be made as necessary. The implementation uses Javascript's Date object and its getTime method to obtain the current time. It uses the browser API's setTimeout function to delay the execution of the loop the specified time period.

The initLoop function implements the algorithm in an internal function. The variable Tpi (the time stamp at the start of the previous frame) is in the scope of initLoop and thus also accessible to the inner loop function. Being in the scope of the outer function allows the variable to maintain its value between executions of the inner function. An alternative way of maintaining this state is to pass the value as a parameter to the loop function every time it is called again. However, using a closure is the cleaner and more semantic approach.

When starting the loop, there is not a previous frame from which to derive a proper deltaT. The implementation runs the loop once with a deltaT of 0 by setting the variable holding the time stamp of the previous frame to the current time right before executing the loop. Then Ti for the first frame will be essentially the same as that variable, creating a deltaT of 0 (or so close to 0 that it's negligible). The loop will then wait long enough before being executed again to have a proper deltaT, and each frame from that point should likewise have a usable elapsed time. 

The initLoop function is public. A developer needs only to require the glob.game.loop module to use it. In future development, however, the looping mechanism will be more often used indirectly. The step function will be defined by a game management module, and it will take care of updating various other modules, such as input and graphics. Rather than defining the step function, the user will configure the other modules' behaviors, and the game management module will create its own step function based on those configurations. The details of this system are still in the works, however. The game management module will be developed as other modules are finished the plans for the overall architecture are more concrete. 

No comments:

Post a Comment