Like 0Likes Dislike Achieving Frame Rate Independent Game Movement

problem movement frame been approach games article question common
The tutorial goes over some small equations to vary game movement based on frame rates and shows modifications made to NeHe's lesson 23 to demonstrate the effect.

Introduction

I often come across the common question, “How do I allow for movement speed in games that is unaffected by frame rate?” While pondering this same question, I recognized the same problem in some games I have written where the object movement has always been too fast when the frame rates were really high. This article is aimed at showing a simple way around this problem. There may be plenty of examples and articles like this already available, but in this article I will offer my own approach to the solution.

In solving the movement problem, there are different methods you can use. One such common approach has been to implement delays to use up extra game cycles on faster computers. An example would be:

while (GetCurrentTime()-starttime<delaytime) {}
This code would loop without doing anything until the difference between the last time taken and the current time is equal to how long you want to delay for. This method can in fact slow down your game, but you would still see some speed differences on faster computers. Also, it can cause games to become choppy on certain machines.

Limiting Movements

A better approach is to change the movement based on how many frames are being rendered every second. To demonstrate this solution, I have modified NeHe’s Tutorial Number 23, which I hope many of you will be familiar with. This particular NeHe tutorial already uses a function for determining time, so we won’t need to perform a large number of modifications to the code.

The basic idea is to determine how much time has elapsed between frames and then change how much we want to move accordingly. As an example, in NeHe Lesson 23 you are walking around a small structure. To move you may want the character to move 2 blocks every second. To move those 2 blocks, all the movements for all the frames you are rendering in one second would have to add up to two. Thus, you must determine how much time is passing between your frames to get the frame rate.

First you must remove the old timer code from the program.

//while(TimerGetTime()<start+float(adjust*2.0f)) {}
The next step is to define some variables in the main function. These are to be put at the top of the WinMain function.

float timer; //used to check the current time
float timerdiff; //used to determine the time elapsed
float secsperframe; //used to hold the value for how many seconds have elapsed between frames
float desireddistance; //desired distance to move in a second
float movementvalue; //value to move by each frame
Next, set the desired distance value to move over the course of a second. I found 2 to be a good number.

desireddistance=2.0f;
If you are getting 80 frames a second then you would want your character to move .025 units every frame since 80*.025 = 2. What you first must do is figure out how much time has elapsed since the last frame. To do this, take the current time before the main loop starts for the first time.

timer = TimerGetTime();

Determining Time Differences

After rendering the scene, compare the current time with the one you last took. We will store this in the secsperframe variable.

//first determine how many seconds elapsed
timerdiff = TimerGetTime()-timer;

//the function reads in milliseconds so convert to seconds by dividing by 1000
secsperframe=(float)(timerdiff/1000.0f);
Let's say the number comes out to be .0125. To get the frame rate, simply divide 1 second by that .0125. This gives you an answer of 80, since 80 times that .0125 is equal to 1 second. To determine how much to move, you simply take the desired distance and divide by the frames per second.
Movement = (desired distance)/(frames a second)
In this example, that would be 1 divided by 80 which would give you .0125 as stated above. The equation can be changed, though, if we substitute in the equation for frames per second. Now it reads:
Movement = (distance desired)/(1/seconds per frame)
This can be further simplified to:
Movement = (distance desired)*(seconds per frame)
I find this equation to be the easiest to use. In NeHe Lesson 23, this looks like:

//now compute the movement value
movementval = (float)(desireddistance*secsperframe);

//get the new time
timer = TimerGetTime();

Moving the character

Now that we have our current movement value, it’s time to put it into the by replacing the old movement code with the new.

if ( buffer[DIK_UP] & 0x80 )
{
//old code
//new code
...
}
These changes can easily be applied for moving in all directions.

walkbiasangle+=(400.0f*secsperframe);