Timing questions

Started by
11 comments, last by Shadowwoelf 15 years, 11 months ago
Ive been reading a lot of articles on timing in games and I am still confused. This is how much I have gathered by myself. 1. You need a framestart variable to basically set the program to 0. Since the internal clock starts as soon as the computer does. So when you run your program the internal clock will return something like 1hour etc. in milliseconds because 1 hour has passed since it was active. and I thought I had more but after that I keep getting confused. Also I was wondering what is the difference between frame time and Fps?
Advertisement
Quote:Original post by Shadowwoelf
1. You need a framestart variable to basically set the program to 0. Since the internal clock starts as soon as the computer does.
If you want to measure time relative to something (such as the start of a frame, or the start of the program itself), then yes, this is important.
Store the time value (e.g. in a variable called framestart) when the program/frame/whatever starts.
framestart = timeGetTime();
Then when you need to get the current time later in your program, you can subtract framestart from it, which will give you the elapsed, or relative time since that event:
elapsedTimeSinceFrameStart = timeGetTime() - framestart;
Quote:Also I was wondering what is the difference between frame time and Fps?

frame time is the length of time elapsed since the last frame. FPS is how many frames can fit into 1 second.
Basically, FPS = 1/frame_time

So if your frame time is ~0.03s then your FPS is ~33
The time returned (and in what units the time is expressed) will depend on the language feature or API you use to query the time. It could be the amount of time that's passed since some date in the past, since the computer was booted up, since the application was launched, or since a 'timer' object was created.

What to do with that data is up to you. A typical approach is as follows (pseudocode):
int lastMS = GetMilliseconds();while (!quit) {    int currentMS = GetMilliseconds();    int elapsedMS = currentMS - lastMS;    lastMS = currentMS;    // ...}
You would then use 'elapsedMS' as the timestep to drive your simulation.

There are many other ways to go about it, of course. If you need more info though, you may have to ask a more specific question.
FPS is the amount of frames that occur in a second(or the average frames per second, over something like the last 10 seconds).
'frame time' how you're using it here, is the amount of time 1 frame is, in milla-seconds.

So: FPS = (frameTime / 1000)


The reasoning for time-based movement/animation/etc in games is due to lag. If you merely limit your games to, say, 50 frames per second, and move the player 10 pixels per frame, if the computer slows down, you might have less than 50 frames for a while, making the entire game move very slowly and the player's actions be delayed as well. This will result in players getting frustrated with your game, if it occurs frequently, or if the slow-down causes their death.

With time-based movement in your games, instead of moving 10 pixels per frame, for 50 frames, you instead move 10 pixels per every '50/1000' millaseconds. If your game suddenly drops to 25 fps, each frame will move the player twice as fast, and to the person playing, his character will be going the same speed regardless of whether he's getting 20 fps, or 50, or 200.

You can implement time-based movement something like this:
//Game startup:unsigned long int currentTime = GetTimeInMillaSeconds(); //You'll have to replace 'GetTimeInMillaSeconds()' with whatever your API offers.unsigned long int deltaTime; //This can be renamed 'frameTime' if it helps any.int playerX, playerY; //Player's location.int playerTime = 0; //Used to 'store up' time that passes, to use to move the player.const int playerSpeed = 100; //Player moves 100 pixels per second.//Main game loop:while(1){    //Update the deltaTime at the beginning of your frame, to be equal to the amount of millaseconds that has taken place since the beginning of the last frame.    deltaTime = GetTimeInMillaSeconds() - currentTime;    currentTime = GetTimeInMillaSeconds();        ...      //Movement code:            //playerTime keeps any leftover time it doesn't use for the next frame.    playerTime += deltaTime;        //Move the player an amount of pixels based off his movement speed and the amount of time past.    if(playerTime > (playerSpeed/1000))     {        int amountToMove = playerTime / (playerSpeed/1000);        playerTime = playerTime % (playerSpeed/1000);                //Move the player 1 pixel for every 10 millaseconds that has passed.        if(PLAYER_IS_MOVING_DOWN)            playerY += amountToMove;    }        ...    }


I hope my pseudo-code didn't over complicate the matter. [laugh] It's actually pretty simple, and this coming from a person who is bad at math.

Read this: Laxyfoo's SDL tutorials - Lesson 32. It uses the SDL API, but the concept can easily be applied to any API, and any language.

Obviously, it can be applied to 3D games as well. And not just movement, but animation, player attacks, physics of falling objects(or any physics), and pretty much anything that relies else on the passage of time.

Well I guess my question is how do I know how much to add to my current time to find out when to update

This is as far as I got


framestart = timeGetTime();
lastframe=framestart
While(!done){
Gameupdate();
Render();
While(timeGetTime()<lastframe+[not sure what to put in here]){}
lastframe=timeGetTime;
}

I want to limit it to around 30fps (2d rpg)

edit: sorry Servant of the Lord you posted while I was replying.
I don't understand what player time has to do in your example. And shouldn't the currentTime be called after you have finished drawing everything?

[Edited by - Shadowwoelf on May 27, 2008 12:29:44 AM]
You can, of course, create an empty loop, but that would be inefficient and ugly (correct me if wrong). Instead use sleep().

const DWORD DesiredFrameLength = 33; // ~30 FPSDWORD StartTime = timeGetTime();DWORD LastTime = StartTime;while(!Done){DWORD ElapsedTime = timeGetTime()- LastTime;if(ElapsedTime < DesiredFrameLength){sleep(DesiredFrameLength - ElapsedTime);ElapsedTime = DesiredFrameLength;}LastTime = timeGetTime();GameUpdate(ElapsedTime );Render(ElapsedTime );}
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
Koobazaur why do you have
ElapsedTime = DesiredFrameLength;

in that if statement when elapsed time will be overwritten when the loop restarts?

And shouldn't the DesiredFrameLength be in the thousands range? because if you first run the program Sleep will only be called every 33 seconds?
That's because the GameUpdate and Render that rely on elapsed time (at least in my implementation) are called before next loop iteration, so your calculation for elapsed time would be off if you didn't re-set elapsed time to desired. If you follow the logic you'll see that these functions will always received the elapsed time equal to desired or greater, whereas if we didn't have that statement in if, occasionally they would get elapsed time smaller than desired followed by one greater than desired. In the end the difference wouldn't be too noticable, but this keeps the elapsed time values passed into update more unform instead of oscilating between big and small.

Also, all times are in miliseconds, not seconds. Sleep will be called whenever your elapsed time is smaller than desired time (less than 33 miliseconds), which is impossible to predict when, as it depends on how long your update and render functions take. May be every single loop, may be never.
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
so DWORD makes 33 into milliseconds?

And with elapsed time I can then use that to move anything on my screen a certain distance?
... no, DWORD is Microsoft type that stands for "double word" which is a 32 bit unsigned integer. There is no data type specicially for miliseconds as miliseconds are just numbers. It's entirely up to you and the rest of your code how you interpret these numbers.

timeGetTime() returns a DWORD value that represents the amount of miliseconds that passed since Windows booted.

read more at: http://msdn.microsoft.com/en-us/library/ms713418.aspx

also, in windows programming (which timeGetTime() is a part of), Microsoft defined custom data types for all the base types (CHAR for char, INT for int, DWORD for a 32 bit unsigned int etc.). This is done because C++ does not guarantee data type sizes, only their minimum (that is, a char is guaranteed to be at least 8 bits, but it may be more on different platforms! ). Hence, custom types are defined to ensure that they are always the same size, regardless of the platform (example: int may be 32bits on one system, but 64 on another, whereas INT will always be 32)

here's a list of all win32 data types: http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx


And as for elapsed time - it's just that, elapsed time. It can be used to make your program run at a given speed regardless of frame rate. You can use it to move your untis (unit.position += unit.speed * elapsed_time), you can use it to animate spries (sprite.frame += frames_per_milisecond * elapsed_time), you get the idea.

A lot of people make FPS bound games and measure the game time via FPS (i.e. move a unit 3 pixels every frame or change animation to next frame ever 3 frames). However, I greatily advise to use actual time itself. It's more accurate, it's more flexible, and your in-game time will not slow down if your FPS goes down. That, and you can still put a limit on your FPS using time, so you aren't losing any functionality.
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...

This topic is closed to new replies.

Advertisement