As a game developer, I'm always looking for better ways to time my
games, and to improve its frame-rate.
My current approach is, to limit the frame-rate to a specified number
of frames per second (i.e. 25 fps). This allows the game to run with
a maximum speed of 25 fps on fast CPUs. Using this method does
solve many timing-problems, but the results are not always satisfying.
Imagine a scrolling ground, that is moved by 3 pixels per frame. With
a frame rate of 25 fps, this results in a smooth scrolling (if you use a
proper timer, like RDTSC or QueryPerformanceCounter). Sadly, on
some video-cards, this will look, as if the screen flickers (even if you
use page-flipping). With 75 fps I could scroll the ground by 1 pixel
per frame, without altering the scrolling speed. If I do so, the flickering
disappears.
But increasing the frame rate to 75 frames per second does not really
solve all problems:
- the target-computer might not be able to display 75 frames per second
- the games overall-speed changes, because there's not only the
scrolling background, but sprites and animations and so on.
So my questions are:
How can I use the maximum possible frame rate, with the rest of the
game running at constant speed (and not warp-speed on fast computers)?
How do I synchronize the graphics with the maximum frame rate
(i.e. scroll by 1 pixel, instead to 3 pixels). The frame rate depends on
the target system, which doesn't make things easier.
How to use multithreading to update the next frame in the background,
before it is displayed? It does not make sense, to *WAIT* for the next
frame, and then draw and flip. In fact, it must be possible to draw while
waiting for the next frame. Anything else would be a waste of precious
time.
Is it possible to implement frame-drops (for slow computers) in a timing
environment like this?
Are there any references or source-snippets on the Internet? I was looking
for some information myself, but... no success.
Any help will be appreciated,
Niki
Could some of this flicker simply be that your chosen frame rate may
not be an integral factor of the video card's frame rate? (Assuming
you're not setting it to 75hz, what if it's running at 60hz? You would
see the results as an uneven frame rate.)-Wm
Ain't we all..
>How can I use the maximum possible frame rate, with the rest of the
>game running at constant speed (and not warp-speed on fast computers)?
>How do I synchronize the graphics with the maximum frame rate
>(i.e. scroll by 1 pixel, instead to 3 pixels). The frame rate depends on
>the target system, which doesn't make things easier.
Here's something I just posted recently (subtle hint: Dejanews!) This
method allows for varying framerates, not only from one PC to another, but
also from one frame to the next.
lastTime = GetTickCount(); // Whatever 'time' function you're using
while( TRUE)
{
curTime = GetTickCount();
elapsedTime = curTime - lastTime;
updateGame( elapsedTime ); // All updates are scaled by the time
// elapsed since the previous frame
renderFrame();
lastTime = curTime;
}
Within the update, you'd be modifying positions/velocities like so (I'm
assuming the use of floating point values per second)
scale = (float)elapsedTime / 1000.0; // Assuming elapsedTime is in ms
xPos += xVel * scale;
yPos += yVel * scale;
This way, you're drawing frames as fast as possible (if you might need a
speed cap, just wait until elapsedTime is greater than the min # of
milliseconds allowed per frame before updating or rendering).
I used floating point numbers. If you want to stick to integers, you could
implement this in fixed-point -- if you're going to scale to time, you'll
need the extra precision.
- Mike
Klaus Hartmann wrote:
>Hi!
Hi Klaus :-)
>
>Imagine a scrolling ground, that is moved by 3 pixels per frame. With
>a frame rate of 25 fps, this results in a smooth scrolling (if you use a
>proper timer, like RDTSC or QueryPerformanceCounter). Sadly, on
>some video-cards, this will look, as if the screen flickers (even if you
>use page-flipping).
Reason being you do _not_ draw every frame. Thus, the human brain can be
irritated. For the following example, let me use some different numbers so I
can skip a bit of math :-)
Let's assume you scroll 60 pixels/second, at 30 fps. Your monitor is running
at 60Hz. At frame 0, everything is OK. At frame 1, your picture _should_
have scrolled one pixel, but it has not. At frame 2, the picture is where it
is expected to be. At frame 3, there's again a difference between the
position the brain assumes and the real picture. This leads to some kind of
flickering.
This gets even worse if
a) The refresh rate is not a multiple of your frame rate.
b) Your refreshs are not exactly locked to the display. If the monitor is
running at 60 Hz, and you update at 30 fps, make sure you're always using
either the even or the odd display frames. If you just update every
_average_ 2nd frame, you could end up having up to 3 frames difference
between two updates, and next time no frame.
Example:
Update Monitor Frame
0 0
1
1 2
3
4
2 5
3 6
>With 75 fps I could scroll the ground by 1 pixel per frame, without
altering the scrolling speed. If I do so, the flickering disappears.
>But increasing the frame rate to 75 frames per second does not really
>solve all problems:
>- the target-computer might not be able to display 75 frames per second
Determine the display rate if you can, and divide it by 2 or 3 to get a
decent frame rate.
>- the games overall-speed changes, because there's not only the
> scrolling background, but sprites and animations and so on.
Move this to a separate thread.
>So my questions are:
>
>How can I use the maximum possible frame rate, with the rest of the
>game running at constant speed (and not warp-speed on fast computers)?
Synchronize to the monitor frame rate. If this is not possible, make your
updates dependant on elapsed time, use a triple buffer and draw as fast as
you can :-)
>How do I synchronize the graphics with the maximum frame rate
>(i.e. scroll by 1 pixel, instead to 3 pixels). The frame rate depends on
>the target system, which doesn't make things easier.
You can query the frame rate using DX. (Sometimes)
Otherwise, you might try timing how long it takes until you can flip again.
>How to use multithreading to update the next frame in the background,
>before it is displayed? It does not make sense, to *WAIT* for the next
>frame, and then draw and flip. In fact, it must be possible to draw while
>waiting for the next frame. Anything else would be a waste of precious
>time.
Let your update routine update all variables relevant to screen redraw into
two alternating buffers. This way, one is always ready, the other one is
updated. If you want to redraw, lock the 'ready' buffer so it does not get
overwritten. Since it was the last recently updated buffer, its state is as
close to redraw time as possible.
If you use *three* update buffers, you can even avoid blocking the update
routine while a redraw is in process.
(When one buffer is locked for redraw, alternate between the other two
buffers)
>Is it possible to implement frame-drops (for slow computers) in a timing
>environment like this?
If you're using multithreading, the frame rate need not be synchronized to
the update rate in any way.
>Are there any references or source-snippets on the Internet? I was looking
>for some information myself, but... no success.
Not that I knew of... If you get any references via e-mail, please post them
here. I'd be interested in it too :-)
Bye,
Robert