FPS and UPS


Apart from FPS, there is another useful measure of animation speed: UPS. The current animation loop carries out one update and one render in each iteration, but this correspondence isn't necessary. The loop could carry out two updates per each rendering, as illustrated by the following code fragment:

     public void run( )     // Repeatedly update, render, sleep     { ...       running = true;       while(running) {         gameUpdate( );   // game state is updated         gameUpdate( );   // game state is updated again         gameRender( );   // render to a buffer         paintScreen( );  // paint with the buffer         // sleep a bit       }       System.exit(0);     } // end of run( )

If the game offers 50 FPS (i.e., 50 iterations of the animation loop per second), then it is doing 100 updates per second.

This coding style causes the game to advance more quickly since the game state is changing twice as fast but at the cost of skipping the rendering of those extra states. However, this may not be noticeable, especially if the FPS value is 20 or higher.

Separating Updates from Rendering

One limitation on high FPS rates is the amount of time that the update and render steps require. Satisfying a period of 5 ms (1000/5 == 200 FPS) is impossible if these steps take more than 5 ms to accomplish. Most of this execution time is usually consumed by the rendering stage.

In this situation, the way to increase game speed is to increase the number of UPS. In programming terms, this translates into calling gameUpdate( ) more than once during each iteration. However, too many additional calls will cause the game to flicker, as too many successive states are not rendered. Each update adds to the execution time, which will further reduce the maximum achievable FPS value.

The new run( ) is:

     private static int MAX_FRAME_SKIPS = 5;       // no. of frames that can be skipped in any one animation loop       // i.e the games state is updated but not rendered     public void run( )     /* Repeatedly update, render, sleep so loop takes close        to period nsecs. Sleep inaccuracies are handled.        The timing calculation use the Java 3D timer.        Overruns in update/renders will cause extra updates        to be carried out so UPS tild== requested FPS     */     {       long beforeTime, afterTime, timeDiff, sleepTime;       long overSleepTime = 0L;       int noDelays = 0;       long excess = 0L;       beforeTime = J3DTimer.getValue( );         running = true;       while(running) {         gameUpdate( );         gameRender( );         paintScreen( );         afterTime = J3DTimer.getValue( );         timeDiff = afterTime - beforeTime;         sleepTime = (period - timeDiff) - overSleepTime;         if (sleepTime > 0) {   // some time left in this cycle           try {             Thread.sleep(sleepTime/1000000L);  // nano -> ms           }           catch(InterruptedException ex){}           overSleepTime =                 (J3DTimer.getValue( ) - afterTime) - sleepTime;         }         else {    // sleepTime <= 0; frame took longer than the period           excess -= sleepTime;  // store excess time value           overSleepTime = 0L;           if (++noDelays >= NO_DELAYS_PER_YIELD) {             Thread.yield( );   // give another thread a chance to run             noDelays = 0;           }         }         beforeTime = J3DTimer.getValue( );         /* If frame animation is taking too long, update the game state            without rendering it, to get the updates/sec nearer to            the required FPS. */         int skips = 0;         while((excess > period) && (skips < MAX_FRAME_SKIPS)) {           excess -= period;           gameUpdate( );      // update state but don't render           skips++;         }       }       System.exit(0);     } // end of run( )

If the update/render step takes 12 ms and the required period is 10 ms, then sleepTime will be -2 ms (perhaps even smaller after overSleepTime has been deducted). This excessive execution time is added to the excess variable, which acts as a total of all the overruns by the update-render calls.

When excess exceeds the iteration period, the equivalent of one frame has been lost. A while loop is entered, which updates the game for each period amount lost, up to a maximum of MAX_FRAME_SKIPS (five updates). The remaining time overrun is stored for use in a later iteration. The MAX_FRAME_SKIPS value is arbitrary, but the larger it is, the more sudden the jump forward in the game may be if the maximum number of frames are skipped.

The outcome is that when a game can't update and render fast enough to match the desired FPS, then additional calls will be made to gameUpdate( ). This changes the state without rendering it, which the user sees as the game moving "faster," even though the number of rendered frames remains the same.



Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net