View Full Version : Constant frame rate in 2D ?
lakibuk
10-27-2003, 08:33 AM
In my last game i used a "dynamic" frame rate. I didn't like the result,the animations weren't smooth.
For my next game i am trying to use a constant frame rate.
Here comes my code, it produces very choopy animation. Anyone knows why?
nowframe=GetTickCount();
while (nowframe-previousframe < 40) { //wait constant time
nowframe=GetTickCount();
}
PrimarySurface->Flip(NULL,0L); //then flip surfaces
previousframe=GetTickCount();
Mark Fassett
10-27-2003, 08:49 AM
Because your game isn't doing anything while it's waiting...
Doing something like the following is better:
nowframe=GetTickCount();
if (nowframe-previousframe > 40)
{
previousframe = nowframe;
UpdateGame();
}
DrawGame();
PrimarySurface->Flip(NULL,0L); //then flip surfaces
gilzu
10-27-2003, 08:53 AM
Originally posted by lakibuk
In my last game i used a "dynamic" frame rate. I didn't like the result,the animations weren't smooth.
For my next game i am trying to use a constant frame rate.
Here comes my code, it produces very choopy animation. Anyone knows why?
nowframe=GetTickCount();
while (nowframe-previousframe < 40) { //wait constant time
nowframe=GetTickCount();
}
PrimarySurface->Flip(NULL,0L); //then flip surfaces
previousframe=GetTickCount();
choppy animation -> low framerate.
try using lower framerate (i'm using 10msecs in Goose Chase).
also, I've learnt just recently (thanks to Anthony Flack) that for some system it will take more than the time you gave it (meaning that it will run slower). think what might happen if it'll take to calculate&render 80msecs? then your game will run x2 slower.
Akura
10-27-2003, 09:14 AM
actually, dynamic frame rate is THE way to ensure smoothness in various machines, if for some reason you are playign at 60 fps and then some anti virus starts scanning your computer, your whole pc will slow down, including the game, if you have a variable frame rate, the game will try to adapt to it, if you have a fixed one, and it is running at slower fps it will look very bad, chopy and slow animations.
Also, i seriously DONT advise to do a XX ms wait then update/draw the game, much better to do:
void frameUpdate ()
{
begin = GetTickCount ();
UpdateGame ();
DrawGame ();
while (GetTickCount - begin < 40)
{
// do nothing, some people like to put Sleep (0) so the game doesn't stall the rest of the machine.
}
}
Fenix Down
10-27-2003, 09:43 AM
I use a framerate independent method similar to this one (http://www.gamedev.net/reference/articles/article1604.asp) . It works great for a high fps (60+), but turned out to be not so good for low fps (such as 30). Problem is at a low fps it tries to compensate for the low fps by increasing how many pixels per frame everything is moving (so at 30 fps everything will move twice as many pixels per frame as at 60 fps). The main problem with this is that it screws majorly with collision detection. Collisions between small objects get missed a lot. I think this can be fixed by running the internal logic of the game at a higher fps than the actual fps of the game, so that internally objects are moving at less pixels per frame and then every Xth internal frame is drawn. But I can't try this until my next game.
ggambett
10-27-2003, 10:19 AM
The "correct" solution to this is to perform the collision detections between the traces of the objects. If the traces collide, you must calculate the time of the collision, as seen from each trace. If the times match (for some definition of "match"), you have a collision.
lakibuk
10-27-2003, 10:24 AM
Thanks for the suggestions, i will try them ASAP.
Dynamic frame rate sucks,sucks,sucks for 2D games, i will never use it again. For 3D it's probably the best solution.
Fenix Down
10-27-2003, 10:29 AM
Originally posted by ggambett
The "correct" solution to this is to perform the collision detections between the traces of the objects. If the traces collide, you must calculate the time of the collision, as seen from each trace. If the times match (for some definition of "match"), you have a collision.
Could you please explain that in more detail? Thanks.
Mattias
10-27-2003, 10:31 AM
I always do the logic at a fixed framerate (usually 60 fps) and let the render run at a variable framerate, as described in http://www.gamasutra.com/features/20010713/dickinson_pfv.htm
I use this for 3d as well as 2d.
Landon_Fox
10-27-2003, 04:17 PM
I do things a little bit different than you guys have mentioned, and I get very satifactory results in my opinion. My system was modeled after console timing though, so it's best used for sidescrollers. Your milage may vary.
What I do is I measure time in frames. There are sixty frames of animation each second, or whatever refresh rate the monitor is at. I use two functions:
void Game_Logic(void) is called exactly sixty times each second.
void Game_Draw(void) is called as many times as possible. On a high end machine this will be sixty (Sync to monitor refresh). On a low end machine this will be less.
I use QueryPerformanceCounter to keep track of time. When it comes time to call Game_Logic, I see how much time has passed since I last called it. I call it as many times I need to in order to keep it at a stable 60 calls a second.
But that's not good enough for me! If you get a hard drive cache that eats up ten seconds, then ten seconds of game play will go by instantly in your game! So I add in a second layer that forces the number of times Game_Logic is called to not increase or decrease more than one frame at a time. This also keeps those system hiccups that eat five frames of time from causing a jagged tear in the scrolling.
The important thing here is that you keep the pixels moving at exactly the same amount each screen refresh. The end result is ultra-smooth scrolling. Anything less and you get chops.
Anthony Flack
10-27-2003, 04:22 PM
I also run the logic at a fixed framerate, and the screen render at a variable framerate.
Mattias
10-28-2003, 01:05 AM
Originally posted by Landon_Fox
I use QueryPerformanceCounter to keep track of time. When it comes time to call Game_Logic, I see how much time has passed since I last called it. I call it as many times I need to in order to keep it at a stable 60 calls a second.
This is exactly what I do as well.
Originally posted by Landon_Fox
But that's not good enough for me! If you get a hard drive cache that eats up ten seconds, then ten seconds of game play will go by instantly in your game! So I add in a second layer that forces the number of times Game_Logic is called to not increase or decrease more than one frame at a time. This also keeps those system hiccups that eat five frames of time from causing a jagged tear in the scrolling.
Won't this cause the game to behave a bit strange? I would imagine it would actually move sort of in slow motion? Or am I just not understanding what you mean?
Myself, I solve this type of situation by simply freezing the game until framerate is back to (or close to) normal. (I keep rendering, but if the number of updates that have to be performed is greater than some threshold, I don't do any of them.)
princec
10-28-2003, 01:32 AM
Humans brains are unfortunately excellent at automatically correcting frame rate discrepancies. I say unfortunate because they actually automatically adapt to frame rate changes already - if you get your program to do the same, it looks awful as the brain completely overcompensates.
If your frame rate starts to drop below 60FPS, you will find that you can still control your avatar and the movements of things still appear as expected. But if you start making things animate faster to compensate it confuses the brain horribly.
Some programmers furthermore like to burn CPU cycles up by executing the game logic at 1000fps. This sort of hack is simply not needed!
The proper solution is to design your game for a minimum specification upon which it achieves a specific minimum framerate. You then cap to this frame rate, and bedamned the machines that fail to reach the minimum specificiation. In this way you can call game logic but once per frame, saving a little power & heat being wasted (it's significant on a laptop, believe me); and you can be assured that motion and animation will be perfectly tuned to the framerate.
There is almost no point in going over 50Hz for motion either, as at this frequency, the brain percieves motion as ultra smooth - however as most monitors run at 60Hz, that's the frequency to aim for. You can get away with dropping down to 30Hz before things really start to look shitty.
Anyone who played games in the 80s will understand all of this without question. Learn from the old wise ones! They figured it out 20 years before you.
Cas :)
Mattias
10-28-2003, 02:04 AM
For me, there are three requirements that needs to be met:
1) The game needs to run at the same speed at all times. If my avatar runs at 5 pixels per second on one machine, he should be moving at 5 pixels per second at other machines as well, even if one is running the game on 5 fps and the other at 60 fps.
2) If the game runs on a fast machine, I want movement and animation to be as smooth as possible. If it runs on a slow machine, I can live with the movement being less smooth.
3) The game needs to be responsive to the users actions regardless of framerate.
Now, I can accomplish this by using a variable framerate. I simply pass the deltatime to my update and scale everything by that. This takes care of 1 and 2. By using buffered input, I can meet req. 3 as well.
Locking the framerate to, say 30, will meet req. 1 and 3, but not 2, as users with faster machines could have smoother movement, but won't have because of the locked framerate.
I have worked on games with both fixed and variable framerates. Both have their pro's and con's but a fixed framerate does not meet all of my requirements. A variable framerate do, but I still miss some of the benefits I would get from a fixed framerate (like knowing when I write the code how much time is going to be processed during update. Like the example with collisions above. It is not entirely necessary to have this, but it certainly makes life easier).
After using this hybrid solution of fixed logic-variable rendering, for quite some time, I can very warmly recommend it. I suspect that once you've used it, you wouldn't want to go back to the other methods.
It is true that you do extra logic updates. But if the machine you are running on is fast enough, you will just be doing one update per render. On slow machines, you will be doing more than one update per render. This isn't JUST wasteful, it is the price you pay for the benefits you get. I think it is worth paying.
On a side note, games in the 80s was mostly played on fixed platforms. On fixed platforms, I would always use a fixed framerate (as I do nowadays on Playstation2 and XBox)
luggage
10-28-2003, 02:12 AM
The methods posted are good ones and do have their advantages and disadvantages.
I favour suppling the update with a delta that's in seconds and using that for calculating all movement. So say I want to move something at 1 metre per second it's be something like x+=1.0f *delta. All of our animation code takes this into account too.
One advantage this method does give you are Max Payne (and a million others) slow motion effects. Just be halving the delta everything will move at half the speed. Stopping entirely can be done (like a pause mode) just by giving it zero. It's also a good test to make sure everything is framerate independant as if the delta is zero all movement shoudl cease.
The bad side to this method is that it can make collisions quite tricky and you will be moving further in 1 step than if the frame rate is poor. This only really happens when the frame rate is extremely poor and the game would be unplayable anyway, we usually just cap the delta so it can't be absolutely huge.
The other method is one similar to how physics systems work (Havok, etc). In that you run the update as fast as you can get away with. One problem with is - what if it's your update that's killing the game? Say you've got an RTS with too many units on themap and your ai is what's causing the problem.
As for just writing your game, working out what the minimum spec is and ignoring people who have something just below. I just wouldn't do that. If your minimum spec for 60fps is something like a P800, that's an awful lot of people to just ignore. Especially as the code to help it to run better isn't exactly difficult. I've worked with programmers who have over 20 years of game industry experience and not at any point did they think that frame rate independance is bad. It's just something they didn't have to worry about.
Back then machines were a fixed spec apart from sometimes having a bit of extra ram. You wouldn't have a spectrum with a different graphics card. You also couldn't spare the extra time on the off chance you might draw too much.
As for the human brain compensating, I'm not sure. Surely you would still need your input to be running quite high? Otherwise you would physically miss key presses and your brain certainly wouldn't make up for that.
Move with the times! I go for the delta method when doing 2d and 3d but I am considering moving back to the update on a fixed framerate for future 2d games.
Scott
princec
10-28-2003, 02:12 AM
Your personal requirement 1) is neither here nor there; you are not actually perceiving a thing moving at 5 pixels per second at all - you are actually watching something moving at 5 pixels per update. It is the update rate which must remain constant or the brain rejects the motion; not the pixel translation. Variable framerate may satisfy your personal requirements but it won't satisfy any customers after something that plays and feels professional, smooth, and slick.
You solve 3) by simply ensuring the target machine's minimum specification can achieve this - a simple step mysteriously avoided like the plague by many developers in here.
Or, there's a trick I did, which switches the game from 60Hz to 30Hz - effectively giving me 35ms to draw a frame instead of 17ms, which has the side effect of halving the minimum system specifications, whilst still being acceptably smooth, responsive, and constant framerate.
Cas :)
Mattias
10-28-2003, 02:23 AM
No, I meant that I want the movement to be 5 pixels per second. With this, I mean that if it takes me 60 seconds to run from one end of the screen to the other, it must take 60 seconds on any machine. If the rendering can't keep up, things will not be perceived as a 5 pixels per second movement, but it will still BE a 5 pixels per second movement.
This is one of MY requirements, and not everone shares them. (and note that this requirement can be met with any of the techniques discussed here)
And yeah, making your game able to run at different fixed rates is quite nice, if you choose to go with fixed framerate.
luggage
10-28-2003, 02:23 AM
I don't understand. If I have a character that moves at 60 pixels a second then. Then to make sure he covers the same difference on whatever the frame rate is.
At 60 fps he will have to move 1 pixel every frame.
At 30 fps he will have to move 2 pixels every frame.
At 10 fps he will have to move 6 pixels every frame.
At 1 fps he will have to move 60 pixels every frame.
In 1 second he will have covered 60 pixels, regardless of framerate. His movement will be constant.
Remember that you don't get a constant frame rate so it can fluctuate anywhere between those values but by using a delta it allows for these plus super fast framerates. Also, unless you specifically choose a 60Hz mode you could get more than 60 fps.
gilzu
10-28-2003, 03:12 AM
Originally posted by luggage
I don't understand. If I have a character that moves at 60 pixels a second then. Then to make sure he covers the same difference on whatever the frame rate is.
At 60 fps he will have to move 1 pixel every frame.
At 30 fps he will have to move 2 pixels every frame.
At 10 fps he will have to move 6 pixels every frame.
At 1 fps he will have to move 60 pixels every frame.
In 1 second he will have covered 60 pixels, regardless of framerate. His movement will be constant.
Remember that you don't get a constant frame rate so it can fluctuate anywhere between those values but by using a delta it allows for these plus super fast framerates. Also, unless you specifically choose a 60Hz mode you could get more than 60 fps.
Placement should be saved as float, it will save you much grief. you can always round it when you want to use it as pixels.
also, you should give GameLogic() a parameter which states how much time has passed since lase GameLogic() was called. this way you can calculate exactly how much to move.
princec
10-28-2003, 03:25 AM
This is missing the point of what I was trying to say:
The brain does not perceive the motion to be at a constant speed.
If your game renders at 60fps at first and then gradually starts to slow down for some reason say to 30fps, the actual physical distance of the sprites movement will be less given a length of realtime. However, the brain works in simulation time, that is, frame ticks, when dealing with 2D. I don't know why it does this - it doesn't do it for Z distance changes (ie. 3D) - only 2D movement.
The end result is though the character has actually moved less in the 60 seconds the brain perceives it to be running at the correct rate regardless - it automatically corrects the perceived speed.
If you adjust the movement of the sprite to compensate it confuses the hell out the the brain and the end result is a horrible, horrible feel which totally ruins any game play.
You can of course argue until you're blue in the face about this, and the only way to do it is to prove it to yourself and write a simple platform game where the object is to jump in a graceful parabolic arc from platform A on the left to platform B on the right repeatedly. First run the simulation in fixed framerate; you'll find that it's dead easy to get the hang of the jump. Then alter the simulation to adjust the framerate up and down randomly using the various schemes introduced in this thread and try to make the jump when the framerate drops. You will find that you can't get the hang of it, and that it feels absolutely awful to play.
Cas :)
luggage
10-28-2003, 03:40 AM
I got how it works :), I mean princec's comment about it being 5 pixels per update. If you move 5 pixels per update this won't be frame rate independant.
gilzu
10-28-2003, 03:46 AM
Originally posted by princec
You can of course argue until you're blue in the face about this, and the only way to do it is to prove it to yourself and write a simple platform game where the object is to jump in a graceful parabolic arc from platform A on the left to platform B on the right repeatedly. First run the simulation in fixed framerate; you'll find that it's dead easy to get the hang of the jump. Then alter the simulation to adjust the framerate up and down randomly using the various schemes introduced in this thread and try to make the jump when the framerate drops. You will find that you can't get the hang of it, and that it feels absolutely awful to play.
Is that a hint? (j/k) ;)
I think youre confusing framerate and what actually happends in the game world. whether a frame was drawn or not, the game logical world continue to "tick".
What i mean, is that the definition of the current frame is "what's the static position of every object in our logically created world moment in this exact moment". To calculate that, you need to consider the time that passed. after 30msecs it will be different then after 60msecs or 45msecs.
Mattias
10-28-2003, 03:50 AM
Originally posted by princec
If you adjust the movement of the sprite to compensate it confuses the hell out the the brain and the end result is a horrible, horrible feel which totally ruins any game play.
Is that so? I have never noticed... you might be right though, i've never compared fixed to variable framerate side by side for a 2d game.
Originally posted by princec
You can of course argue until you're blue in the face about this, and the only way to do it is to prove it to yourself and write a simple platform game where the object is to jump in a graceful parabolic arc from platform A on the left to platform B on the right repeatedly. First run the simulation in fixed framerate; you'll find that it's dead easy to get the hang of the jump. Then alter the simulation to adjust the framerate up and down randomly using the various schemes introduced in this thread and try to make the jump when the framerate drops. You will find that you can't get the hang of it, and that it feels absolutely awful to play.
I think I will actually.. I'm quite curious about what the difference will be... I'll post results here when it is done.
princec
10-28-2003, 03:51 AM
Not in the "2D Game Design Pattern" it ain't :)
I feel like a crumbly old teacher trying to convince a class full of unruly students about quantum mechanics (the explanation of which totally defies logic too) :/ Surely there are some wizened old timers in the thread who know what I'm on about?
Cas :)
princec
10-28-2003, 03:54 AM
Mattias - if you've really got the time to do that it would be great, and post it up for all to see, because it's an invaluable proof for games programmers to get their heads round.
Cas :)
Mattias
10-28-2003, 03:59 AM
Yes, will do.
For 3d, there's no question, I've done the side-by-side compares, and variable framerate is the way to go, unless you have a fixed platform.
I've never done the same sort of comparison for 2d.. It just seems ok when I've tried it at a variable rate.
luggage
10-28-2003, 04:37 AM
You can of course argue until you're blue in the face about this, and the only way to do it is to prove it to yourself and write a simple platform game where the object is to jump in a graceful parabolic arc from platform A on the left to platform B on the right repeatedly. First run the simulation in fixed framerate; you'll find that it's dead easy to get the hang of the jump. Then alter the simulation to adjust the framerate up and down randomly using the various schemes introduced in this thread and try to make the jump when the framerate drops. You will find that you can't get the hang of it, and that it feels absolutely awful to play
Have I misunderstood here? It doesn't seem like a fair comparison. Surely you need to write fixed frame rate code then give it a variable frame rate. Then write variable frame rate code and also give it a variable frame rate.
Varible frame rate code works just as well as fixed frame rate code if the frame rate is consistent.
If the point is that a fixed frame rate is better then it's a no brainer - of course it is. The problem is on a pc the frame rate is rarely fixed. It's one of the reasons why on the PS you are better to lock your frame rate at 30fps rather than have it fluctuate between 40-60. Having it run creamy smooth at 60fps and then drop to 40 is a killer and looks very messy.
princec
10-28-2003, 04:42 AM
Ah good :) You agree with me then.
On Win32 you can reasonably easily sync to monitor refresh if you're fullscreen (and also set monitor frequency to your desired framerate or a multiple thereof) to get perfectly smooth tear-free drawing. Otherwise you need to spin on the hires timer in user mode which looks like it's gobbling CPU cycles, but if you do a Thread.yield() or whatever its C equivalent is in the loop, you'll achieve a system-friendly frame rate limiter.
Cas :)
Carrot
10-28-2003, 04:54 AM
Definitely on the older home computer such as the c64, the frame rate was locked at a constant 50Hz (at least in europe. Does this mean C64 game played faster in the US?).
This was possible because the system was constant for everyone.
A couple of points though: even when drawing every other frame on a 2d_scroller on the c64 (meaning 25Hz) still produced a smoothly moving game. The smoothness seemed to stem from the consistency between frame rates over time, rather than how high the frame rate actually was. Smooth animation is generally achievable at only 10-20Fps.
Another thing worth mentioning is that the temporal responce of the human eye is slightly below 50Hz which means that the human brain is used to filling in gaps in movement, but its not used to variable eye-frame-rates!
princec
10-28-2003, 05:04 AM
I think the cells in the eye only manage a mere 10Hz at best and the brain does a lot of complicated jiggery pokery to figure out what's going on. At about 50Hz the brain is given so much interpolation information relative to the rate at which the eye cells can respond, it perceives everything as totally smooth.
Films can run at 24Hz and appear smooth because the individual frames are actually already motion blurred (that's how film works). If you shoot video at 24Hz it appears really strange and surreal because it's composed of totally still images with no blurring. To get round this you shoot video at twice that rate and it all looks normal again.
Computer games that run at 30Hz or less only appear to be smooth until you play the same game at 60Hz. Try Alien Flux in both modes, one after the other (Options checkbox) - one of the best illustrations of the effect around, if I may say so :D
Cas :)
Mattias
10-28-2003, 05:15 AM
Originally posted by luggage
Have I misunderstood here? It doesn't seem like a fair comparison. Surely you need to write fixed frame rate code then give it a variable frame rate. Then write variable frame rate code and also give it a variable frame rate.
Yes, I agree, that is what you would have to do if you wanted to generally compare fixed framereate to variable framerate under real-world conditions.
What I'm interested in here is to see if the controls and the fun in a simple platform-jumping application with variable framerate is really that terrible compared to exactly the same application with fixed framerate.
Of course, a constantly high framerate, running at the refresh rate, would be the best. But I want to see if the variable framerate approach to solving the worst-case scenario is really so bad that you are better off limiting your framerate to a much lower fixed rate.
Landon_Fox
10-28-2003, 08:02 AM
Matthias wanted to know if the second part of my algorithm makes things work strangely. Yes and no. It depends on the system. If the amount of available cpu cycles is constantly changing, then yes. If it's stable except for the occasional disk cache or something like that, then it's quite smooth. That's why it included an option to turn the timing off.
However, now that I sit down and think about it PrinceC has a very good point. Has anyone ever tried to play an old DOS game on Win ME? There is a lot of stuff that interferes with the DOS vsync interrupt. The result is that it would miss it a couple times each second. If it had a timing mechanism to compensate, it caused jagged tears. If you just ignored the loss of one frame, it looked a lot better. One game in particular, stargunner, was overzealous in it's frame smoothing and would stay skipping two frames for a few seconds after a system hiccup. The ship DID always move the exact same amount in the same time, but it felt like it was way sped up. Hmm.
Of course you realised you just invalidated a piece of code I had a lot of fun creating. :(
I do see one problem though. Gradius Syndrome. The best strategy in that game is not to take the most useful weapon, but the most graphically intensive ones. Load up on options and you'll bring the SNES to it's knees. After the game slows down to about a third of it's normal speed, it's much easier to dodge the hailstorm of bullets flying at you.
lakibuk
10-28-2003, 08:49 AM
...and i still don't know how to get a constant frame rate. Tried Akuras methode but it didn't work in my app.
@Akura: did you actually try this code or were you only thinking that i could work like this?
princec
10-28-2003, 08:59 AM
Here's what I used in AF, which works properly for machines over and above minimum spec. but will start to judder on lower machines. Also, I've got vsync enabled - miss a frame deadline and framerate halves, then thirds, then quarters, etc. - but there's no tearing at all.
// Do the game logic:
update();
// Now do all the rendering:
render();
// Swap buffers
paint();
// Now wait until the frame time is up
float elapsed = 0.0f;
do {
long now = Sys.getTime();
elapsed = (float)(now - then) / (float)Sys.getTimerResolution();
if (frameTime == 0.0f) {
frameTime = elapsed;
}
Thread.yield();
} while (elapsed < options.getFrameTime());
Sys.getTime() returns the Win32 hires counter. options.getFrameTime() returns either 1/30 or 1/60.
Cas :)
lakibuk
10-28-2003, 09:10 AM
Thanks a lot. The code looks similar to Akura's. There probably is some other problem in my code.
Akura
10-28-2003, 09:10 AM
yes I have, if you want, you can send me the update part of code and I'll take an hack at it.
A few things, GetTickCount can be about 20ms innacurate (meaning it will MESS up your frame rate) on Windows 2000 (and I guess WinXP). Best option is to use QueryPerformaceCounter and QueryPerformanceFrequency as someone mentioned (if you use C++, I have a class that may help you out), but this requires a multimedia (or hardware) timer and is dependent on, well, the hardware. I think most computers from the last 4 years or so support for it, but you never know. Another way is to use timeGetTime and put your program between timeBeginPeriod and timeEndPeriod. (By default, timeGetTime on Windows 2000 can be 5 milliseconds off). I personally just use QueryPerformanceCounter myself.
Here is a sample on how to use timeGetTime:
#include <windows.h>
int main ()
{
// Set timer resolution to 1 millisecond
timeBeginPeriod (1);
while (1)
{
// Store start frame time
int iBeginTime = timeGetTime ();
// Do game stuff
UpdateGame ();
DrawGame ();
// While difference in time is less than 33 milliseconds (1000ms / 30 fps) do nothing
while (timeGetTime () - iBeginTime < 33)
{
Sleep (0);
}
}
// Reset timer resolution
timeEndPeriod (1);
return 0;
}
This code has problems if the UpdateGame and DrawGame take longer than 33 ms since they should be updating at that time. But that is a problem with constant frame rates, you should always ensure you don't get lower than you need. And that is why I recommend variable frame rate, if you do it well, you can get the game working perfectly at 60 fps :) or 15 fps :)
ps: I didn't check if this compiled, there may be some typos there :)
Jeff Greenberg
10-28-2003, 10:13 AM
@Cas:
Just a small, but imortant, correction to your remarks about film and video frame rates: Film is shot at 24 fps, but when it is projected there is a shutter that spins 2 to 3 times in front of each frame, so you are actually seeing 48 to 72 "updates" per second in the theater, depending on the projector. This was done precisely for the reason that 24 fps is a bit too stuttery for most people, but the "artificial" updates, even using the same frames, smooth out the motion considerably. Film transfered to video is, of course, shown at 60 fields per second NTSC, 50 fields per second PAL, or at other rates depending on the application.
@Everyone:
I think that frame rate indpendent movement, overall, is a good thing, but frame rate variable movement, as in compensating the frame rate during the course of a game, is not so desirable. If you can do some testing at the start of a game and lock in that frame rate (or use Cas's methods to change the FPS in predictable ways), then you are probably going to be fine. It is changing the frame rate in unpredictable ways during the course of a game that can be distracting. It is clear to me that when seeing something like 40 updates one second, then 27 the next, it is easy for my brain to perceive the change, regardless of how accurate is the position of the moved obect.
Now for some hypothesizing:
I think it is also a reasonable hypothesis that the brain is attuned to the frequency of updates in such a way that a change in this frequency is likely to be interpreted, at first, as a change in the apparent motion of the object, regardless of the accuracy of the plotting of the movement. Consider that for a person to follow a moving object or apparently moving object, they must move their eyes every so often (their own personal "update") to keep the object near the centers of the retinas of their eyes. This is done partly by anticipation (I'll have to dig out the reference for this), so changing the frame rate will mean that the eye may look at a certain space for the next update, but it won't be there. Instead, it will appear at a slightly later time, in the correct position, or at a slightly earlier time, still in the correct position, but in each case displaced from where the brain was expecting it. Even if the person moved their eyes to the next place where they were expecting the object, they would be wrong. The brain will, of course, compensate... until the next frame rate change.
**EDIT:
Of course, the brain has to deal with changing rates of motion in everday life as well, but in those cases the brain is heavily influenced by expectations: gravity, friction, perspective, etc. When frame rates change in a 2D game, these things are likely to be slightly off or even bizarre.
This might not only create cognitive dissonance for a person playing the game, but also might cause the brain to do extra work to reaquire the object so that it can be tracked again. During the reaquisition, the frame rate may have changed significantly again, causing a further backup in the "processing" done by the brain and possibly wasted "cycles" trying to anticipate uneven patterns in the change of frame rates. Constantly changing frame rates could play havoc with one's sense of motion as the brain adapts, reaches a stable state, then must adapt again.
And this is not even taking into account the brain's use of peripheral vision to detect motion, which in many cases could probably be interpreted as movement of a new object, even though it may be the same object, but in an unexpected place.
At high frame rates all of this would likely not be a significant problem because the object would be near enough to where the brain expects it to be to not raise any red flags. However, with lower rates it would be much more obvious.
Akura
10-28-2003, 01:43 PM
@Cas: just a couple things :) Where do you setup the then variable ? Maybe it's the beer but I can't see it there :)
Also, if :
Sys.getTimerResolution() is the equivalent of QueryPerformaceFrequency, the I strongly advise you to store it at the beginning (it never changes). You are doing a cast of a LONGLONG (64 integer) to a float (which isn't that fast) then diving it. It isn't much, BUT heck, it is cleaner if you just do
float InverseTimerFrequency = (float)Sys.getTimerResolution();
and then multiply it :) Seems ridiculous but heck, if you can optimize, why not ?
@Jeff: I have no idea about the validity of your questions, but remember that if you have a fixed framerate (60 fps for example) and your eye gests accostumed to it then, as soon as you miss drop a frame, the eyes would notice the slow down (as they would be expecting the image to be somewhere else :)) while using a variable frame rate, the time it takes to update is different, it shouldn't be noticed. If a image moves 3 units in a frame and 6 in another, BUT the frame took 1/2 of the time to display, I think your brain would be smart enough to move the eyes twice the distace :)
Of course, this is all based on your hypothesis also and I have no clue what our brain/eyes do :)
Anthony Flack
10-28-2003, 04:08 PM
I'm running my logic at 300-odd updates a second, and my screen update however many hz the monitor is set to - or less if the machine can't quite hack it.
Running the logic this much IS wasteful, however my game logic seems to run fine on a p 200, although on the graphics side it really needs a GF2 or thereabouts to reach full speed. So given the disparity between cpu requirements and gfx card requirements, I don't think that's a problem in my case.
If the graphics card is up to it, you'll get smooth motion locked to the monitor refresh. On slower machines it will be choppier, but still quite playable. It's better than having the game run in slow-motion - I mean, you can't really be reccommending the game run in slow-motion can you?
Jeff, your explanation about following an object makes a lot of sense... If the eye/brain are really working like that, then it seems obvious that it is better to slow down the game logic instead of compensating the slowdown by moving the object more pixels than usual..
BTW, when I played Alien Flux I didn't notice any problem, but at the end of each game it tells me that it's running too slow and I should switch to 30Hz. When I tried that, the game was horribly jerky :P .. So I switched back to 60Hz and disabled that requester.
About the 24Hz movies, well, I certainly don't find these to be smooth. When there's a side travelling it's so jerky I can barely stand it.
lakibuk
10-31-2003, 03:14 PM
Still don't get a smooth constant frame rate.
Could someone be so kind and take a look at my code.
You can download (56KB) it at:
http://www.edu.uni-klu.ac.at/~khofer/snoop.zip
The file contains my animation .exe and the main.cpp. In main.cpp look at the WinMain(..) function at the bottom of the code. There the action takes place. I use Akura's method with timeGetTime.
thanks in advance.
Akura
10-31-2003, 03:51 PM
Heya, I can't be sure without seeing the rest of the code, BUT, are you scaling the movement of your sprite ?
For example, lets assume we want it to move 100 pixels per second, remember, when you update, if it is running at 30 fps, there will be 30 calls to update, so you would increase its position by 3 each time, BUT if you are running at 60 fps it would be called 60, so you would call increase its position by 1.5 each frame, and so on. Unless you are externalizing g_duration and using it inside the update files, I think you forgot this step, of course, if you haven't then I'll look pretty dumb :)
So to close it do something like
Sprite::Update (int iDuration)
{
x += iDuration / 1000 * pixels_to_move_per_frame;
y += iDuration / 1000 * pixels_to_move_per_frame;
}
[edit I changed the division, I must learn to not post when I'm half asleep :)]
Which basically will calculate how many milliseconds have actually passed and multiply the movement by it :) (Remember to make X and Y floats and make the appropriate casts or else you will get bad results:) ) Of course, if you are looking at fixed frame rate, you will probably only have one case for this, SO the update will always be the same, but your app currently has various.
munsie
02-25-2004, 09:38 PM
"You can of course argue until you're blue in the face about this, and the only way to do it is to prove it to yourself and write a simple platform game where the object is to jump in a graceful parabolic arc from platform A on the left to platform B on the right repeatedly. First run the simulation in fixed framerate; you'll find that it's dead easy to get the hang of the jump. Then alter the simulation to adjust the framerate up and down randomly using the various schemes introduced in this thread and try to make the jump when the framerate drops. You will find that you can't get the hang of it, and that it feels absolutely awful to play. "
100% AGREED and CORRECT!!!
It's doesn't matter what's happening "internally". In a 2D twitch game, (shooter, platform, etc) visual timing on the screen is EVERYTHING! Even dreaded slow down is better than a fluctuating frame rate. Because the player's brain will also compensate for the slow down and "time" his recations.
If "Mario" needs to have 10 frames of animation while jumping from platform to platform, the gamer better see all 10 frames so he can time his jump!
3D standarrds have caused a wealth of new 2D game coders to be fogged. :) LOL...
lakibuk
02-25-2004, 10:32 PM
I finally came to the conclusion. PCs aren't suited for constant framerate. Will stick to dynamic rate now in all future games.
princec
02-26-2004, 12:28 AM
But why? They seem to to perfectly well at constant frame rate for me.
Cas :)
munsie
02-26-2004, 03:25 AM
Seems like alot of coders are stuck on this "high frame rate" bandwagon. How many frames per second did Myst run at? Ok, I know...but seriously a 2D game doesn't have to run at 60-80-400 fps to be enjoyable.
I just downloaded and installed a side scrolling shooter called "Platypus" that runs at around 12-15 fps on my system. But this game is GREAT and has amazing graphics. A very graphic intensive 2D game that runs anywhere from 15-30 frames per second is acceptable. Hey, if you guys want to code time based movement for 2D games, more power to ya. But there are advantages programming wise AND end user wise for NOT using time based movement.
Larry Hastings
02-26-2004, 09:38 AM
Perhaps you can't have a rock-steady constant frame rate on PCs, but you can see it from here. :) I remember discussing variable frame rates somewhere (flipcode? gamedev.net? not sure) and most of the people who had tried 'em went back to constant frame rates.
Here's what I do. I have a class called a "minder" that regulates my frame rates. You tell it how much time has passed, and it tells you whether or not it's time for a new frame. I have two of these; one for advancing game state, and one for rendering to the screen. The game minder always updates at 120fps, and the screen minder attempts to update at the chosen refresh rate of the current resolution.
So the code looks kinda like this:while (gameIsRunning)
{
DWORD elapsed = getCurrentTime();
gameMinder.addDelta(elapsed);
while (gameMinder.timeToUpdate())
{
readInputs();
computeGameState();
}
screenMinder.addDelta(elapsed);
if (screenMinder.timeToUpdate())
drawScreen();
}This is a greatly simplified form of what I actually use. (For instance, the above doesn't support pausing games... I use a third minder, slaved to the gameMinder.)
Note the while loop on the gameMinder.timeToUpdate(). If the delta fed into the game logic minder is larger than, say, two frames, you still want those frames to elapse, so the game logic still runs at an average of 120fps, even if it isn't rock-steady. (I realize this means reading the input twice in a row, and it likely hasn't changed in that tiny fraction of a second... well, those are the breaks.)
However, you don't want to catch up mindlessly. If your machine really hiccups, and starves your game for time for let's say a whole second, you don't want your game to first freeze for a full second, then leap forward a full second. So the minder is also configured at startup with a "catch up threshold", which is the maximum amount of time it is allowed to fall behind--beyond that and it just throws away the extra time. The "game logic" minder will catch up only up to 1/5 of a second; the screen minder won't "catch up" at all, as there's no point in rendering two screens back-to-back.
This built-in slippage means minor hiccups are smoothed over, but major gaps don't mean the game jumps around on you unpleasantly. Since moving to this system, my game has run smoothly on all but the most overtaxed systems. I highly recommend it.
Anthony Flack
02-26-2004, 05:50 PM
Crap, Platypus only runs at 12-15fps on your system? Too much 2d blitting for your gfx card? Oh well!
Glad you still enjoy it; but it's definitely much better at 60FPS!
Hello all.
I just wanted to add my 2 cents on my experience...
When I was at one place, any game delivered to our test department failed certification if it had a variable frame rate. Our graphics guru (you probably own books from this guy) argues for constant frame rates along the same lines that princec is championing here.
This of course lead to *a ton* of arguments between us coders on what is the best way to handle frame rates. I simply trusted the opinions of our resident expert (maybe even foolishly, but I doubt it).
Some devs just cannot get over the mental block with high-end graphics cards and FPS (i.e. they want to brag about running Quake3 at 200 FPS and feel cheated by locked frame rates). I contend that some one on a low end machine should have just as enjoyable an experience as someone with a $3000 monster. From a marketing standpoint, it is those low-enders that make your game a big seller instead of just a critically acclaimed piece of software that is bundled with graphics cards.
One caveat though: these were games made for mostly for consoles, so some will naturally argue that it's different on PCs.
munsie
02-27-2004, 05:53 AM
Larry,
While I totally understand what you are doing there, anytime you "average" that's a cap on the frame rate. A better solution in my mind would be to allow the user to run a "blit test" somewhere in the config setup. Let it run for a few seconds and determine the average frame rate and then "lock" the game at that frame rate. Any of those hiccups that occur, will then only cause a slight blip in the action. And the user could enjoy the best "constant" frame rate for their machine's abilities.
I see no reason to run "the logic "any faster than the graphic updating. UNLESS you are coding a real time adventure simulation.
What I have decided to do with my games is the following:
a) Code a small "generic" function to test the blitting of the computer and return an average fps. This would be used as a starting point fps for the "first time the user" sees the game.
b) TELL them very clearly at game start up (perhaps only one time when the game runs for the first time) that in order to mazimize their gaming experience they may need to adjust the frame rate.
c) In a config section somewhere, allow the user to switch between time based and frame based movement. (If the game is capable of running in either mode.)
d) Allow them to manually change the fps the game is running at. Perhaps a slider from 60 down to 12. (Or somthing around those numbers. :)
What does everyone think of this?
---------------------------------------------------------------
Hi Anthony!
That's your puppy? (Platypus). Yah, it only runs at best 15 fps on my dev sustem. But with all of that parrallax scrolling you have going on, you are doing A TON of blitting! :) Seriously, I hope you are enjoying some good sales, because that game graphically is just amazing. Congrats! If you don't me asking, how are you handling the movement of this game? Time based, frame based? Thanks!
Larry Hastings
02-27-2004, 07:52 AM
Originally posted by munsie
anytime you "average" that's a cap on the frame rate. A better solution in my mind would be to allow the user to run a "blit test" [...] I see no reason to run "the logic "any faster than the graphic updating. UNLESS you are coding a real time adventure simulation.Ah, but there's a very good reason to do so. The whole point of running my game clock at a fixed average rate means that all characters move at fixed rates too. If you want the Space Goblin to cross the screen in two seconds, and you're running your game clock at a fixed average rate of 120fps, you set his speed at (screen width/120) and you're done. It's true that the user won't see the intermediate states, but if you want the Space Goblin to move at a steady rate across the screen on everyone's machine, and some people run at 85fps and some people run at 60fps... sure, you can do it, but you're just making work for yourself.
There are other benefits. Doom 3 uses a fixed game clock updating at 60fps; previous iD games used a flexible game clock, I believe updating game state in lockstep with screen updates as you propose. This had some funny side effects on their physics system--there are some jumps in Q3A that you can only make at certain (very high) frame rates. I bet that was caused by compounded round-off error on the large number of steps. A fixed game clock means the game behavior is more consistent across machines.
By the way, I found the discussion I dimly remembered! It was posted as a Flipcode Tip Of The Day by Javier Arevalo of Pyro Studios--he's the lead graphics programmer on the Commandos series. And he's a proponent of fixed step game loops. Here's (http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-MainLoopTimeSteps&forum=totd&id=-1) the original TOTD from Flipcode, and here (http://jare.planet-d.net/docs/FixLoop.htm) is Javier's permament (and perhaps updated) page for for that article. I suggest you read the Flipcode discussion--lots of folks had very insightful comments IMHO. And most of 'em were for rather than against fixed time step game clocks.
As far as capping the number of updates to the screen, that's only relevant to my screen clock. And guess what: I cap my screen clock at the current screen's refresh rate. You can draw at 8000fps if you like, but if the user's monitor only draws at 60fps that's all they're gonna see. It's true that my game clock is locked, but that's 120fps... I suspect that is high enough to be enjoyable. :)
I don't see the need for the "fps you want the game to run at" slider. Surely every user wants the game to run at as high an FPS as possible. Why would someone want to set it artificially low?
Mike Boeh
02-27-2004, 08:13 AM
Platypus should run at 60 fps on just about *any* system with an 8 meg card. Perhaps you have the nvidia drivers that had 2d hardware accel disabled.
Running a game at a fixed fps internally, and rendering out at the refresh rate is what all of my games do- I don't see what the big deal is.
munsie
02-27-2004, 08:40 AM
wow! Some really cool reading there. Thanks Larry. The whole "logic at x frame rate" and "render at another frame rate" still doesn't click for me. I'm an old skool "one loop, top to bottom" coder so in every loop everything gets done, input, logic, render, etc. For me a constant frame rate thinking applies perfectly. And regarless how fast a computer can render these days, I do think a 2D game running at a stable 15, 20 or 30 fps is fine. That's quick enough for responsive input and smooth animation. Looking at this thead and the links you posted it does seem overall that most coders would rather code with a constant frame rate in mind. Some really good reading here. :)
Still this baffles me...
"Which is the case, because we run a game logic tick 15 times per second (TICK_TIME = 1000/15), while displaying at framerates in the range 20-60 frames per second.."
Logic at 15 times per second and render at higher speeds? How can the visuals run faster than the logic then? Doesn't this cap how fast the graphics can move around the screen?!!?!? :)
Norbyte
02-27-2004, 08:48 AM
Originally posted by Mike Boeh
Platypus should run at 60 fps on just about *any* system with an 8 meg card.
I tried Platypus on an ATI Radeon 9200 128MB, and the frame rate was very low for me too (looked like around 15 fps).
Mike Boeh
02-27-2004, 08:48 AM
Here is the original blitz code I wrote for anthony to run logic at a fixed rate, and render at the refresh rate.
munsie
02-27-2004, 08:54 AM
"Platypus should run at 60 fps on just about *any* system with an 8 meg card."
Sorry, I just installed it on a 32mb graphics card on a Sony Vaio and it runs very slow. :( But love those graphics!!
Larry Hastings
02-27-2004, 12:12 PM
Originally posted by munsie
"Which is the case, because we run a game logic tick 15 times per second (TICK_TIME = 1000/15), while displaying at framerates in the range 20-60 frames per second.."
Logic at 15 times per second and render at higher speeds? How can the visuals run faster than the logic then?That's from Javier Arevalo's article, yes? Well, just goes to show you that you should read the whole article. :) What you missed: he also interpolates between the current frame and the next frame, based on current speed (and acceleration I guess). Strikes me as a little odd, but I guess it's a worthwhile tradeoff between calculating their game state too often (which I guess is expensive) and providing the user with a visually stimulating experience.
munsie
02-27-2004, 12:12 PM
"I don't see the need for the "fps you want the game to run at" slider. Surely every user wants the game to run at as high an FPS as possible. Why would someone want to set it artificially low?"
In my tests, lots of things cause the frame rate to flucuate greatly, including an active dial up connection, virus checkers, etc. So while the system may "jitter" a bit at 60fps, it might be rock solid constant at 30 or 20 fps. So why not let the user tweak the frame rate?
Larry Hastings
02-27-2004, 01:10 PM
Originally posted by munsie
So while the system may "jitter" a bit at 60fps, it might be rock solid constant at 30 or 20 fps. So why not let the user tweak the frame rate?I just don't see the advantage to the user. It'd be one thing if, by artificially limiting the frame rate to 20fps, you ensured that it would never drop below that. But you can't; all you've accomplished is an artifical cap on the frame rate. Your game will still experience the same "jitter" due to the external events you name.
Anyway, given the choice between "a rock-steady 20fps" and "shooting for 60fps but occasionally dropping to 20fps", I'd definitely go for the latter. More frames, you see.
My opinion is with the old guard here ;)
If I'm in the middle of some intense action and suddenly for (insert reason) the framerate's temporarily slowed down, one of two things will happen depending on the system:
1. The framerate's locked, and so it all moves slow for a while, but I'm still in control and I can see what's going on.
2. The framerate is dynamic. As a result, things are actually SLOWER for a decent while because of all the fancy calculation needed to figure out what happened during that temporary situation where no frames were drawn. By the time I see the next frame, my character's probably dead or severely crippled.
The biggest good point of 2 is that if you can't quite reach a target FPS, you'll still be playing without slowdown. But that doesn't necessarily make it preferable.
Larry Hastings
02-28-2004, 02:26 AM
Originally posted by RTF
My opinion is with the old guard here ;) [...] As a result, things are actually SLOWER for a decent while [...]Aha! I think I see what's going on here--we've been talking past each other.
When I said "frame rate", I meant "screen refresh rate, which is independent of the game state update rate". (See my previous postings in this thread for how I have two independent clocks.) I bet when munsie (and you, RTF?) said "frame rate" you meant "screen refresh rate and game state update rate combined", yes?
Personally I don't want to allow the game updates to slow down ever. I see that as an exploit--"hey! I know how to make Space Goblins easier! just run your protein folding program at a high priority! when I do that on my computer, Space Goblins runs at about half speed!" If the screen refresh starts taking a long time on the user's computer, they need to drop their resolution IMHO.
So in a way I am agreeing and disagreeing at the same time. I agree that a fixed game state clock is a necessity. But I also think you should allow the screen refresh rate to be dynamic, but always striving for the high end.
p.s. Hey, RTF, I used to live in Santa Cruz--that's where I got my BA in CS. I still miss Tacos Morenos and King Chwan. But I don't miss the traffic!
munsie
02-28-2004, 03:38 AM
For what's it worth,I just wanted to say thanks to those who have participated in this thread over the months (years?). :) I'm new here and this thread alone has been some of the most valuable reading I have come across since I started coding games again. (after a 10 year break!) LOL....
jaggu
02-29-2004, 02:55 AM
And its not over yet! I've got a 0.002 paisa to put in.
class CGameLoop {
/*
TICKS_PER_SECOND can be calculated with
time.h functions (portable but 32 bit precision only) or
QueryPerformanceCounter (Win32 only, C/C++) or RDTSC instruction
(x86 only, inline assembly or ASM/OBJ and link)
*/
// game logic runs at 100 fps - change as suits you.
const __int64 FRAME_INTERVAL = TICKS_PER_SECOND / 100;
__int64 elapsedTime;
const int MAX_RECENT_FRAMES = 10;
int numRecentFrames;
list <__int64> recentFrameTimes;
void frame (); // render a frame
void time (__int64 t); // set time taken to render a frame
}
void CGameLoop::frame () {
// draw the frame
// read input
bool evaled = false;
while (elapsedTime >= FRAME_INTERVAL) {
/*
evaluate the game state/logic once every FRAME_INTERVAL
which ensures it runs at the same rate on all sorts of machines.
*/
evaled = true;
elapsedTime = elapsedTime - FRAME_INTERVAL;
// do game logic (apply input, physics, ai, etc)
}
// discard remaining time for smoother motion
if (evaled) elapsedTime = 0;
}
CGameLoop::time (__int64 t) {
/*
sets the time taken to run
CGameLoop::frame (). it averages the 10
most recent run times of CGameLoop::frame ()
so that a partcularly long frame
(eg, due to a hard disk access) doesnt
let the game logic update many times leading to
jerky motion.
*/
// using <list> from STL ...
if (numRecentFrames == MAX_RECENT_FRAMES) {
recentFramedTimes.pop_front ();
--numRecentFrames;
}
recentFramedTimes.push_back (t);
++numRecentFrames;
__int64 sumRecentFramedTime = 0;
for (ListOfInt64Iterator iter = recentFramedTimes.begin (), jter = recentFramedTimes.end (); iter != jter; ++iter) sumRecentFramedTime += *iter;
elapsedTime = elapsedTime + (sumRecentFramedTime / numRecentFrames);
}
Now in your windows idle loop do,
while (true) {
if (PeekMessage (...)) {
// normal mesg processing.
} else {
// run game loop
// assume gameLoop is a declared var
// _rdtsc () is my own function to read time stamp counter in x86.
//
__int t1 = _rdtsc (); // set time stamp
gameLoop.frame ();
gameLoop.time (_rdtsc () - t1); // set frame time
}
Does this put this thread to rest. I bet not!