Sign in to follow this  
pcmattman

Player Movement Independent of Frame Rendering

Recommended Posts

Hi everyone, I'm having some trouble at the moment making movement in my game smooth and consistent. At the moment the player is moved when each frame is rendered, so when the framerate drops the player moves slower (and when it goes up the player moves faster). I play other games and it doesn't have these problems. Is there any way (other than using a thread - I tried that and it just slowed everything else down) that I can make player movement independent of rendering frames? How do commercial games do this?

Share this post


Link to post
Share on other sites
One approach is to scale all of your motion according to how much time has elapsed since the last time the Update code was called, but this can be tough if your code wasn't designed to handle this from the start. Plus there are rounding errors that can pile up.

Using a fixed time step may solve the problem. Simply wait a little bit between updates such that the time it takes to complete one pass of the game loop remains constant. This is ideal for simple games which wouldn't benefit from extra processing.

If neither of those sound good to you, do some research on game loops. Being the most fundamental aspect of game programming, you'll easily find several resources on the matter.

Share this post


Link to post
Share on other sites
The biggest problem I've found is when I do limit the FPS in order to get consistent motion it still varies.

Before I limit the framerate, I can sometimes get an average of 60 FPS, but if I limit to 30 I only average around 25, which I don't fully understand.

I'll have a look into game loops and see what I can find.

Share this post


Link to post
Share on other sites
Quote:
Original post by pcmattman
The biggest problem I've found is when I do limit the FPS in order to get consistent motion it still varies.

Before I limit the framerate, I can sometimes get an average of 60 FPS, but if I limit to 30 I only average around 25, which I don't fully understand.

I'll have a look into game loops and see what I can find.


Why are you setting it to 60 fps? Are you developing for an NTSC television or something? If you're on a console then that's expected. If you're on the PC, you should be rendering "as fast as possible", which normally means rendering everything and waiting around for your buffers to flip, then immediately rendering again. Assuming you leave vsync on, the graphics should essentially mirror the monitor's refresh rate -- anywhere from 50Hz to 120+Hz.

As far as your timing goes, what are you using to delay between frames? Nearly all of the delay and sync functions operate with time slices, which run about every 10 to 16 ms (adjustable). If you are using one of these routines, you'll have a very hard time getting 'exactly' your target rate.

Share this post


Link to post
Share on other sites
Assuming you are using DirectX and C++ ...


class Player
{
public:
D3DXVECTOR3 velocity;
void Update(void);
int LastUpdate;
D3DXVECTOR3 position;
};

void Player::Update(void)
{
int UpdateTime;


UpdateTime = GetTimeInMiliSeconds();

position += velocity * (UpdateTime - LastUpdate);

LastUpdate = UpdateTime;
return;
}





GetTimeInMiliSeconds() should use wither QueryPerformanceFrequency() and QueryPerformanceCounter() which are quicker(i think) and more accurate or GetTickCount() which is easier to implement.

~ I enjoy spoon feeding

[Edited by - ganbree on December 31, 2007 7:01:43 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by ganbree
Assuming you are using DirectX and C++ ...

*** Source Snippet Removed ***

GetTimeInMiliSeconds() should use wither QueryPerformanceFrequency() and QueryPerformanceCounter() which are quicker(i think) and more accurate or GetTickCount() which is easier to implement.

~ I enjoy spoon feeding


You're spoon feeding bad information though. You should not storing the elapsed time in milliseconds - for simple games this will be rounded down to zero because it will be called so fast. A better solution would be something like my stopwatch. However, you are correct in sugesting the use of QPC - this is a Windows specific API call that can query the time on the cpu clock down to the nano second - plenty accurate enough!

It's the same principle as above, but here's a slightly more complete implementation:


/// <summary>
/// Represents a stopwatch, that is accurate down to nanoseconds.
/// </summary>
public class Stopwatch
{
private readonly long frequency;
private long lastTime;

/// <summary>
/// Creates a new Stopwatch, and starts it.
/// </summary>
public Stopwatch()
{
if (!NativeMethods.QueryPerformanceFrequency(ref frequency))
throw new InvalidOperationException("Hardware does not support high frequency counters");
Reset();
}

/// <summary>
/// Resets the stopwatch, and starts it again.
/// </summary>
public void Reset()
{
if(!NativeMethods.QueryPerformanceCounter(ref lastTime))
throw new InvalidOperationException("Hardware does not support high frequnecy counters");
}

/// <summary>
/// Returns the time since lap was last called.
/// </summary>
/// <returns>A double containing the time since Lap was last called, in seconds.</returns>
public double Lap()
{
long currTime = 0;
NativeMethods.QueryPerformanceCounter(ref currTime);

double elapsed = (currTime - lastTime) / (double)frequency;
lastTime = currTime;

return elapsed;
}
}



This is C# , but it's not really doing anything C# specific so it should be easy enough to implement. You would use it like this:

Stopwatch timer = new Stopwatch();
....
while(true) {
double elapsed = timer.Lap();
character.position = character.velocity * elapsed;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by frob
Quote:
Original post by pcmattman
The biggest problem I've found is when I do limit the FPS in order to get consistent motion it still varies.

Before I limit the framerate, I can sometimes get an average of 60 FPS, but if I limit to 30 I only average around 25, which I don't fully understand.

I'll have a look into game loops and see what I can find.


Why are you setting it to 60 fps? Are you developing for an NTSC television or something? If you're on a console then that's expected. If you're on the PC, you should be rendering "as fast as possible", which normally means rendering everything and waiting around for your buffers to flip, then immediately rendering again. Assuming you leave vsync on, the graphics should essentially mirror the monitor's refresh rate -- anywhere from 50Hz to 120+Hz.


60 FPS is as fast as possible for me at the moment. All of the DX SDK samples run under 10 FPS on my system as well, so I'm a bit confused as to how to speed that up.

ganbree: Thanks for that snippet (it may not be correct but it gives the general idea).

Cycles: Thanks for your class, I'll try it out today. I assume that the velocity would be a vector? And that the velocity vector would be all zero until the player hit the "move forward" key (at this point it would then have the velocity data added)?

Thanks for all your help!

Edit: I'm now getting much better framerates (in excess of 200 FPS) - I didn't realize that by default DX9 waits for vertical sync (DX8, which I converted from mid-project, doesn't).

[Edited by - pcmattman on December 31, 2007 11:06:41 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this