Player Movement Independent of Frame Rendering

Started by
10 comments, last by pcmattman 16 years, 3 months ago
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?
Advertisement
update the players position based on a constant rate of speed over time. this way the players location will be correct no matter what the frame rate is.
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.
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.
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.
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]
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;}
Oliver Charles (aka aCiD2) [ Cycles Blog ]
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]
You sure? All versions of DirectX that I remember using would wait for vsync by default.
I'm pretty sure it's not default in DX8, as I was able to get massive framerates when I was still using it.

This topic is closed to new replies.

Advertisement