Game Timing...

Started by
7 comments, last by Xorcist 22 years, 9 months ago
Just curious, what is the best method of game timing, and what is a decent throttle value. Currently I use the following: Pseudo Code:
  
Set Constant Throttle in Milliseconds
Main Game Loop
  Get Start Time
  Select Case GameState
    Demo
    Intermission
    Playing
    Paused
    GameOver
  Get Finish Time
  if ((Finish - Start) < Throttle) then
    pause for (Throttle - (Finish-Start)) milliseconds
Loop
  
Right now my Throttle is set to 10ms... it that too small? Originally I had it set to 250ms, but I thought that was too high. Is there a way to determine the best throttle value for a game? Any advice and or new timing algorithms would be appreciated, thanks. P.S. Slightly off topic but... is there an advantage to creating seperate internal loops for each of the the various game states? Currently I just call the appropriate procedure which ultimately returns to the main game loop to re-check the game state and perform timing each cycle. It seems like a lot more work to create seperate loops for each state, but someone mentioned it to me once and I just wondering if there were any benefits in doing so.
Advertisement
why restrict it at all? just use frame-based modeling where you move your objects like this:
object_x=speed_x*throttle
object_y=speed_y8throttle
throttle is more commonly called delta, but it doesn''t really matter.

HHSDrum@yahoo.com
Polarisoft Home Page
My HomepageSome shoot to kill, others shoot to mame. I say clear the chamber and let the lord decide. - Reno 911

Urgh. It bugs me when people do that to time their games.

I recommend either:

1. Keep track of your loop time, and multiply all your physics movement by the last loop time (that way people with faster machines will get better frame rates).

2. Keep track of loop time, and run your logic every X hz, render every Y Hz, take input every Z Hz, etc ... so, let''s say you want the following rates:

Logic   =  20Hz =  50 millisecondsInput   =  10Hz = 100 millisecondsPhysics = 100Hz =  10 millisecondsRender  = as fast as possible  


So, get the last loop time and add it to each of separate logic, input, and physics timers. If enough time has ticked by to run logic, run the logic, and subtract 50 from the logic counter. If enough time has ticked by to poll input, poll input and subtract 100 from the input timer. If enough time has ticked by to do the physics, do a physics run, and subtract 10 from the physics timer. Note, if your last loop time was, say, 25 milliseconds, you will run physics twice. Then, once per loop, (if anything has moved) do a render. Alternately, you can render every frame, and interpolate positions, but this is more difficult.

Both methods have their pros and cons. I have used both.

Throttling (your method) works, but has the disadvantage that faster computers will get the same frame rate as slower computers, and if the computer is slow enough to run slower than your throttle value, everything will look slow-motion.








Here''s my method:
  //------------------------------------------------------------------------// Name: WaitTime()// Desc: Waits for time to pass//------------------------------------------------------------------------bool WaitTime(int time){	static int CurrentTime = 0;	static int LastTime = 0;	int        TimeDelta = 0;#ifdef WIN32	if (LastTime == 0) // first init		LastTime = GetTickCount();	CurrentTime = GetTickCount();	TimeDelta   = CurrentTime - LastTime;	if (TimeDelta >= time)	{		LastTime = CurrentTime;		return true;	}#endif	return false;// use it like this...void GameMain(){  if (!WaitTime(150))    return;   // do game stuff here....}  


It works good for me, although it may not be the most effective counter int the world....
Hope that helps

Anonymous Poster, do you know of any good tutorials and or examples of the method you described. I''d like to look into it further. For my current project (a simple pacman clone) I just needed a constant frame rate, which is why I choose the easy way out. But I plan to work on some bigger projects and would like to know not only how to implement a better timer, but the pros and cons behind using it.
Xorcist, here''s is the frame-delta code I use. Its the best way to time your game, though the only problem is if the game runs at >200FPS, DInput may stumble so just make sure you limit the FPS to 60-75FPS via your DirectGraphics init routine.

    // Global variablesfloat    g_fCalcDelta;__int64  PerfTimerRate;__int64  PerfTimerDivider = 0;// Call this on game initbool InitPerfTimer(void){  __int64 tempInt64;  // Aquire the timer frequency  if(!QueryPerformanceFrequency((LARGE_INTEGER*)&PerfTimerRate))  {      return FALSE; // System doesnt have a Performance timer   }  // Check the rate (usually 1193180)  if(PerfTimerRate==0)  {      return FALSE;  }   // Calculate millisecond divider  PerfTimerDivider = (__int64)( (__int64)PerfTimerRate / 1000);  if(!QueryPerformanceCounter((LARGE_INTEGER*)&tempInt64))  {      return FALSE; // win errors  }  return TRUE; // Success}WORD FTime(void){    __int64 tempInt64;    QueryPerformanceCounter((LARGE_INTEGER*)&tempInt64);    return (WORD)((_int64)tempInt64 / (__int64)PerfTimerDivider);}// Call this every frame to get the frame diff.void UpdateTimeDeltas(){    static WORD timerDelta = 0;    static WORD oldftime = 0;    static WORD newftime = 0;    static WORD oldnDiff = (WORD)FTime();    // Calculate the frame delta.    newftime = FTime();    if( oldftime > newftime ) oldftime = newftime;    timerDelta = newftime - oldftime;    oldftime   = newftime;    float fCalcDelta = float(timerDelta / 1000.0f);    // Set the global fCalcDelta and counter.    g_fCalcDelta = fCalcDelta;}// Call every frame to update the sprite positions.void UpdateSprites(bool bLeft, bool bRight){    // Player velocity    vel = 100.0f;    if(bLeft)  Player.xpos -= g_fCalcDelta * vel;    if(bRight) Player.xpos += g_fCalcDelta * vel;        // Note ''Player.xpos'' is a float variable.}  As for the background scrolling, give your background and main sprite a global position, and whenever you update the position of the main sprite, at the same time update the position of the background minus the sprite offset of the main sprite.For example (640x480):      void SetBgndPos(){    // Center the player.    Level.xpos = WORD(Player.xpos) - 320;    Level.ypos = WORD(Player.ypos) - 240;}void UpdateFrame(){    // Set the Bgnd pos in relation to the player pos.    UpdateTimeDeltas();    UpdateSprites(..DInput status..);    SetBgndPos();    // Blit the background tiles.    Blit(Level.lpDDSurface, Level.xpos-640, Level.ypos);    Blit(Level.lpDDSurface, Level.xpos, Level.ypos);    Blit(Level.lpDDSurface, Level.xpos+640, Level.ypos);    // Blit the sprite    Blit(Player.lpDDSurface, 320, Player.ypos);    }    


Note; The Blit() function would be your own routine.

Hope this helps


  Downloads:  ZeroOne Realm

  Downloads:  ZeroOne Realm

SikCiv,

Personally I prefer rendering at a specific framerate, as it simplifies many things. But if you want to run as fast a possible why don''t you thread the input routines so that whenever you get data from directinput you change some state variables, that why you are running your main loop full tilt without the bother of waiting around for windows to keep up.

Xorcist,

Fixed or as fast as possible both have advantages, but one thing to think about is will your game have reproducable behavior? can you replay a sequence of events and get the same results? Take a look at one of the recent features from gamasutra.com on the subject.

Cheers
Snowmoon,
If you rely on the framerate, what happens when the framerate is slower than 60-75FPS? The gameplay and sprite movement will slow down and may render the game un-playable on slower systems. With the frame-delta method you can garantee smooth gameplay no matter what the framerate is, though I guess it depends on how complicated the game is. In my case I need it to be precise since it my game consists of hundreds of sprites with varied velocities, the higher the framerate is, the smoother everything moves.

As for the DInput stall, it wasnt specifically a DInput problem, more to do with the video card reference drivers I was using - the GeForce256 can run at 400+ FPS with the refresh wait disabled resulting in a delay in other game functions - most noticably the user-input. I fixed the problem by installing the proper Asus drivers and everything is fine now

  Downloads:  ZeroOne Realm

  Downloads:  ZeroOne Realm

SikCiv,

Generally I don''t shoot for 60.. I''m shooting for 30fps so the
bar is quite low to begin with. If the game notices a slowdown
where it is missing a signifigant number of redraws it starts
skipping drawing some frames. I''m also reliant on character
animations that are based on a specific framerate.

I like the idea up top where each logic function takes a set
ammount of time, but I''m not sure how you would resolve the
spacial anomolies from doing the physics calcsand due to fp
rounding the object is not quite where is it supposted to be.

Cheers

This topic is closed to new replies.

Advertisement