Skip to main content
gamedev.net
🔒 Locked

Limiting FPS

Started by danielk Jun 16, 2002 at 1:08 PM 32 replies 3.8k views
Original Post
danielk
danielk
Hey! Quick question people! I''m attempting to limit the FPS of a demo on really fast machines, but also to speed it up on slower machines! I grabbed this from a post by Zaphos, which should give the effect I desire: ************************************* logicalTime = GetTime(); while(!done) { // or whatever your main game loop is while(GetTime()>logicalTime) { DoLogic(); logicalTime+=intervalSize; //if you wanted 60 logic updates per second and GetTime were //in terms of milliseconds, for example, this would be //60.0/1000.0 } DoFrameDrawing(); } ************************************ The above code aparrently should limit the program to 60 frms per second on fast machines by skipping logic frames and rendering more often, whilst on slower machines, it would perform the logic routines at 60fps but render less often, giving a jerkier framerate, but running at the same speed on a faster machine...I think (:0) But when I implement this into my code, my program gets caught in the main while loop. intervalSize increments by 0.06 and never catches up to GetTime() (by the way, I''m using GetTickCount() to recieve the current time in milliseconds), at least I think thats the reason. When I increment by 0.6 things seem to work better.... I''m just a little confused by the the whole thing (:0) Any suggestions of what I can do? Thanx people! Transformers Rulez!!
Transformers Rulez!!
IndirectX
IndirectX
quote:
Original post by danielk
Any suggestions of what I can do?


Yes, implement framerate-independent logic and don''t limit framerate at all.
---visit #directxdev on afternet <- not just for directx, despite the name
LockePick
LockePick
quote:
Yes, implement framerate-independent logic and don''t limit framerate at all.

That''s definately the way to go. I mean, if someone could go at 120 fps, the game still moves at the same rate but looks much smoother!
www.gametutorials.com has a time-based movement tutorial. It''s really simple to implement.

------------
aud.vze.com - The Audacious Engine <-- It''s not much, yet. But it''s mine... my own... my preciousssss...
MSN: nmaster42@hotmail.com, AIM: LockePick42, ICQ: 74128155
Lord FlatHead
Lord FlatHead
I''ve got this little function that gets the framerate (time the last frame took to render) on each frame, and use that to determine the speed of things. Like if I want the player to move at 2 units per second, I do like "player.xspeed += 2.0f * time;" Seems to work fine.

_________
"Maybe this world is another planet''''s hell." -- Aldous Huxley
___"Maybe this world is another planet''s hell." -- Aldous Huxley
Bad Monkey
Bad Monkey
And another thing... give GetTickCount a big raspberry, and use a real timer function. In your case, I would recommend timeGetTime() ...you can use it as a drop-in replacement for GetTickCount, but its resolution is actually 1ms (rather than GetTickCount''s 50-or-so-whenever-I-get-around-to-it ms)
IndirectX
IndirectX
quote:
Original post by Bad Monkey
but its resolution is actually 1ms

On NT, this is only true if you use timeBeginPeriod/timeEndPeriod to set timeGetTime to that resolution. The default is about 5 ms I believe.
---visit #directxdev on afternet <- not just for directx, despite the name
Dactylos
Dactylos
For the most accurate timing on the Windows platform you should use QueryPerformanceCounter() and QueryPerformanceFrequency(). The performance counter is not always available though (depends on the hardware), so you should still have a fallback using timeGetTime().
IndirectX
IndirectX
In this case, don''t forget about the nice feature performance counter has.
---visit #directxdev on afternet <- not just for directx, despite the name
Bad Monkey
Bad Monkey
In this instnace, I actually chose to recommend timeGetTime over QueryPerformanceCounter for a number of reasons:

- timeGetTime is faster
- he most likely doesn''t need the extra resolution
- the lovely feature of the performance counter that IndirectX kindly pointed out

Trust me, just use timeGetTime. (IIRC, its in winmm.lib)

Thanks for pointing out that other resolution issue IndirectX... I forgot to mention that
Dactylos
Dactylos
quote:
Original post by IndirectX
In this case, don''t forget about the nice feature performance counter has.

Hmm, I didn''t know about that. Thanks.

Jedi of Myth
Jedi of Myth
Hmmm, I would still recommend PerformanceCounter over timeGetTime. I have noticed extremely jerky time based movement using timeGetTime on my labs'' P4s with Windows 2000.

I asked one of the Black Robes why the Deceiver wasn''t going to stay to defend the dam, and he tersely replied: "He goes to warn the Emperor; moving through odd angles, faster than any man, and if unobserved, much faster than that."
I asked one of the Black Robes why the Deceiver wasn't going to stay to defend the dam, and he tersely replied: "He goes to warn the Emperor; moving through odd angles, faster than any man, and if unobserved, much faster than that."Elemental Engine: ryan_lurvey.tripod.com/engine.html
javaguerra
javaguerra
What I''m doing in my current game is letting directx define the framerate (The monitor''s refresh rate keeps it at 60fps or lower). And I try to optimize stuff so that it doesn''t go below 60fps. I don''t know about OGL.

The problem that I see with framerate independent logic is best explained with the following example:

Suppose that the main character is running towards a hole in the ground as the user prepares to jump over it. But then, the framerate goes down but the user won''t be able to see accurately when he needs to jump because frames are skipped.
But maybe this only applies to fast action games.

What do you think of this? is this a bad aproach?

--
Jose Manuel Guerra
jmguerra@guerragames.com
http://www.guerragames.com
--Jose Manuel Guerrajmguerra@guerragames.comGuerraGames
IndirectX
IndirectX
quote:
Original post by javaguerra
What I''m doing in my current game is letting directx define the framerate (The monitor''s refresh rate keeps it at 60fps or lower). And I try to optimize stuff so that it doesn''t go below 60fps.

Well, this sucks. I have a nice monitor which can handle 1600x1200x32 @ 85 Hz, which is my desktop resolution, and there is no excuse you can give me for locking me to 60 Hz refresh rate. Is it really so hard to implement framerate-independent motion? Framerate locking is a workaround which IMHO arises from your laziness. There are cases where you need to lock framerate if you *really* know what you''re doing, but this case isn''t one of them.
---visit #directxdev on afternet <- not just for directx, despite the name
CheeseGrater
CheeseGrater
First of all, don''t let these guys discourage you. Frame rate independant logic isn''t always the right way. You don''t get repeatable behavior that way, for one thing.

The best of both worlds is what you''re trying to do: Locked game logic updates with an unlocked render loop.

For a really great explanation and sample code, check out this link.

Particularly check out the MAX_LOOPS check he''s got in there. You might be having that problem with your code.
Palidine
Palidine
quote:
Original post by CheeseGrater
You don't get repeatable behavior that way, for one thing.


explain that.

the whole concept of framerate independant logic is to give you repeatable behavior regardless of the speed of the machine on which the game is running. when i play quake on a 66Mhz machine or a dual processor 1.4Ghz machine the character moves EXACTLY the same subjective speed. but it looks a million times smoother on the newer system b/c i get a higher framerate.

i have yet to come across an example where limiting the framerate is a better solution than framerate independant logic. i'd definitely be down to finding an example for curiosity's sake.

-me



[edited by - Palidine on June 17, 2002 3:25:51 PM]
CheeseGrater
CheeseGrater
quote:
Original post by Palidine
explain that.




OK, sure.

First, when I say repeatable, I mean that given the same set of inputs, you arrive at the same result.

The one of the problems with a framerate independant system is that rounding error will accumulate at a different rate depending on the speed of the machine. In single player games this isn't usually a problem.

Say you want to record a demo, though. If you want to just record keypresses, and play those back into the game later to get a replay of the game, that won't work with framerate independant logic. When you're on a different machine, game entities will end up in subtly different positions, and those differences will usually get larger over time.

This is also a concern for network games with client side prediction, since client predicitons of server events will be at their most accruate when the rates of physics intergation are the same. That means you want to run your client logic at the same rate as the servers to minimize the frequency of full state resyncs.

There's a reason Quake/Halflife, tribes, etc. run their physics/AI at a fixed rate and their display as fast as possible.


[edited by - cheesegrater on June 17, 2002 3:37:17 PM]
Kern
Kern
My games runs in fullscreen and aren't limited by the refresh rate of the screen, I get around that like they did in Quake3. Quake3 runs in widowed mode but on a fullscreen window. You can configure your window for the refresh rate you wan't in your settings but keep in mind that the way windows work is as follow:
The game refreshes it's "image" whenever it wants but windows will present the last image when it's time for a refresh. If you have a Screen refresh of 60 and your game runs at 100 you will only see 60 of those 100 images. But you can also see 2 parts of different images at a time if your game changes it's "image" when windows is presenting it to screen.

Fixed logic is a must, otherwise movement will not be the same even if you divide the speed and rotation corectly, an acceleration of 10m/s 10 times isnt the same than 20m/s 5 times.

There is even a reason to limit the graphic refresh rate, trying to do a maximum number of refresh can make your fixed number of logic jerky.


[edited by - Kern on June 17, 2002 4:08:53 PM]
Palidine
Palidine
CheeseGrater: good example i''ve been thinking there must be a use for frame limited coding.

quote:
Original post by Kern
Fixed logic is a must, otherwise movement will not be the same even if you divide the speed and rotation corectly, an acceleration of 10m/s 10 times isnt the same than 20m/s 5 times.



well depends on how you do your logic. if you''re doing everything like: position = position + velocity. obviously you''re going to break when framerate goes up. but if you do position = position + velocity * timeSinceLastFrame, you get consistent velocity/acceleration no matter what the framerate is. the latter is how i have movement implemented in my current engine work and everything moves at the same speed across computers w/ different frame-rates. the only problem you run into with that is what CheeseGrater was talking about with faster accumulation of rounding errors. that amounts to small differences in movement but nothing that is percecptable from the users standpoint (only perceptable from a replay scenario).

-me
Kern
Kern
Palidine : If you do anything in your logic routine with a DeltaT then your taking big risks. Like I said, even if you divide your speed by the DeltaT it''s not going to change the fact that acceleration divited by DeltaT isn''t going to work right. For example:

Object Speed 5/sec
Object Accel 1/sec
Object speed over 30 sec at a rate of 5 sec and then 10 sec.
5, 10, 15, 20, 25, 30, 35.
5, 15, 25, 35.
Object position over 30 sec, at a rate of 5 sec and then 10 sec.
25, 75, 150, 250, 375, 525, 700.
25, 175, 425, 775.

And the multitasking Windows always causes some small slowdown from time to time, these result in a large DeltaT and creates errors.
Palidine
Palidine
quote:
Original post by Kern
Palidine : If you do anything in your logic routine with a DeltaT then your taking big risks. Like I said, even if you divide your speed by the DeltaT it's not going to change the fact that acceleration divited by DeltaT isn't going to work right. For example:

Object Speed 5/sec
Object Accel 1/sec
Object speed over 30 sec at a rate of 5 sec and then 10 sec.
5, 10, 15, 20, 25, 30, 35.
5, 15, 25, 35.
Object position over 30 sec, at a rate of 5 sec and then 10 sec.
25, 75, 150, 250, 375, 525, 700.
25, 175, 425, 775.



nope. you're doing the math wrong. i did too at first and was ready to cede the point... but i finally got it and it doesn't matter what your deltaT is, the answer will always come out correct.

the physics equation is s = s0 + v0 * t + 1/2 a0 * t^2

s0 = position at last calculation
v0 = velocity at last calculation (this turns out to be the real key)
a0 = acceleration at last calculation

you have to calculate velocity of each turn and save it for use in the calculation of the NEXT cycle.

so codewise:

/**
* assume oject CGameObject has member vars position, velocity and
* accel whose values are persisisted between calls to update
*/
void CGameObject::update(float dT) {
position = position + velocity * dT + 1/2 * accel * dT * dT;

//update velocity to current velocity, we will use this number
//next time in the above equation
//it's CRUCIAL to have this AFTER the pos calculation
//so that the velocity in the above equation is the vel at
//the PREVIOUS calculation point

velocity = velocity + accel * dT;
}


i've got an excel spread sheet up here (right-click and saveLinkAs... to view). It simulates the actions that this code would create, if you want to play around with it. it's w/out virus (as far as my updated work machine can tell me).

i set up 3 tables with different timeSteps (0.5, 1, 0.33) to simulate different framerates. note that at similarly numbered total time-elapsed points the position values are all exactly the same. rounding errors WILL eventuall accumulate to generate different numbers but from a subjective point of view the change will not be significant in terms of user percieved object movement.

with the numbers i used (const accel 3, initial vel and pos = 0) i'm only off by 0.02 out at 70seconds.

as CheeseGrater mentions, these slight differences WILL be significant from a repeatable AI behavior point of view.

-me

[edited by - Palidine on June 17, 2002 5:53:32 PM]

[edited by - Palidine on June 17, 2002 6:02:48 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.