|
|
| fps and timer stuff |
|
lucaz
Member #4,194
January 2004
|
I tested a game sketch with a powerful PC, and it was completly unplayeable because it rans too fast!. 1-How can force the game to run no more than 60fps? |
|
Rampage
Member #3,035
December 2002
|
2. I think timers are implemented in a thread, so they shouldn't slow down your system too much. -R |
|
Nunca Ese
Member #5,262
November 2004
|
1.- // fps counter #define FPS_RATE BPS_TO_TIMER(60) volatile unsigned int fpsTimer = 0; void FPS_FUNC() { fpsTimer++; } END_OF_FUNCTION(FPS_FUNC); Use the timer to run the stuff you want 60 times per second:
|
|
umperio
Member #3,474
April 2003
|
Isn't better to let all the logic update at 60 fps and render at the best speed the computer can? I think human eye can still feel the difference between 60fps and 75fps, so if I can run at 75fps why not? |
|
flares
Member #3,463
April 2003
|
i agree with umperio [nonnus29]Plus the api is crap ... I'd rather chew broken glass then code with those. |
|
FMC
Member #4,431
March 2004
|
Umperio said: Isn't better to let all the logic update at 60 fps and render at the best speed the computer can? I think human eye can still feel the difference between 60fps and 75fps, so if I can run at 75fps why not? I'm not sure of this but if you only update the logic 60 times per second there is no point (and no graphical improvement) in reblitting the same image over and over... better use this time to yield to the OS or whatever [FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites] |
|
Marco Radaelli
Member #3,028
December 2002
|
Mithrandir said: I'm not sure of this but if you only update the logic 60 times per second there is no point (and no graphical improvment) in reblitting the same image over and over... better use this time to yield to the OS or whatever Well if there's no logic update there's no changes between two frames, so yielding would be nice, but I would replace yield_timeslice() with rest(1)
|
|
Nunca Ese
Member #5,262
November 2004
|
Yea, Marco and Mithrandir got the answer. No sense in drawing if no logic changes. For sprite animation its better if you know that you will display 60fps and no more than that, so you can set your animations to the movement rate you want, and test them the same rate that they will be drawn in every computer (every computer that can do your 60fps) IMO. But it depends on the game. You can also set considerations about the game time if you are making a real time game (time lost due to drawing, ...). You can read this article from Javier Arévalo (Commandos saga) for nice example. --- |
|
Derezo
Member #1,666
April 2001
|
Quote: No sense in drawing if no logic changes. There's no down side, from a performance or visual perspective. Use page flipping. I would highly not recommend using rest(1). On a windows machine, this means it's going to rest for approximately 10ms (and do nothing in that time). If the machine is a slower one, this time is valuable and can lead to loss of logic cycles and/or loss of video frames. The best solution is to use page flipping with a lock on the fps of your logic. You wont get tearing, and your game will run at a decent speed on all systems. On slower systems, you'll get choppy video but not choppy or slow logic. "He who controls the stuffing controls the Universe" |
|
Erkle
Member #3,493
May 2003
|
If you rerender the same screen again(not just blit or flip it) it may still be rendering when the next logic step should have been running. This leads to small skips in the game that make fast moving objects look jerky.
If the writing above has offended you, you've read it wrong.....fool. |
|
lucaz
Member #4,194
January 2004
|
I changed your example a little, but I don't understand how it works while(!key[KEY_ESC]) { if(lastFrame >= fpsTimer && lastFrame != UINT_MAX)) { yield_timeslice(); continue; } lastFrame = fpsTimer; // stuff }
|
|
jamal
Member #3,326
March 2003
|
you can lock the fps this way :
I didn't know about the yield_timeslice function, but don't understand what it does, so i will continue with this stuff instead |
|
gering
Member #4,101
December 2003
|
Quote: I would highly not recommend using rest(1). On a windows machine, this means it's going to rest for approximately 10ms (and do nothing in that time). If the machine is a slower one, this time is valuable and can lead to loss of logic cycles and/or loss of video frames. On a windows machine you schould use Sleep() and timeBeginPeriod(). Don't forget timeEndPeriod(). __________________________________________________________ |
|
tobing
Member #5,213
November 2004
|
On Windows rest() is implemented using Sleep(). And why should rest(1) wait for 10ms? My measurements indicate that rest(1) waits fpr 1ms average - slight variations possible, so that's not too exact. You have approx. 1000 rest(1) calls within a second. |
|
FMC
Member #4,431
March 2004
|
Gering said: On a windows machine you schould use Sleep() This is what, AFAIK, yield_timeslice(); does under windows. Tobing, when people say that rest waits for 10ms it's because (i don't know where i read it) allegro's(or it's windows's fault?) implementation of the timer isn't precise to the millisecond. BTW what Marco is saying is valid for a WIP (i don't recall which one) where yield_timeslice, under windows, didn't work as expected. [FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites] |
|
jamal
Member #3,326
March 2003
|
I don't see why use Rest would resolve the problem because, regardless of while (!game_over) { while (speed_counter > 0) { update_game_logic(); speed_counter--; } update_display(); while(speed_counter == 0){/*do nothing*/} }
|
|
Nunca Ese
Member #5,262
November 2004
|
lucaz said:
I changed your example a little, but I don't understand how it works Not the right way. You should use: while(!key[KEY_ESC]) { if(lastFrame >= fpsTimer && lastFrame != UINT_MAX)) { lastFrame = fpsTimer; // stuff } yield_timeslice(); } Explanation:
Using draw out of the if condition for painting more than 60 times can be used to scroll, page flipping or this kind of stuff they say, but u really dont need it (maybe my way make the minimum requiriments higher). In my game (in progress 40%) input phase includes logic and scroll calculation, so i dont need to paint the same frame (no tick, no changes). This will probably change when i add the AI, so ai can use the free time to improve its performance. @lucaz (lastframe < fpstimer) { lastframe = fpstimer; // stuff } or (fpstimer > 0) { fpstimer = 0; // stuff } I think you can control time better using the first solution. jamal said:
while (speed_counter > 0) { If computer is slow at a certain moment speed_counter will grow a lot. If cpu gets free later, cpu will try to do this amount of counter that couldn't do, so you will have a really fast moment on the game. (Dont know if i have explained it well; i mean, that you have to control lost frames in a moment, and no extend them to later; if so, later will have more than 60fps, what can be a bad effect for animations). jamal said:
// yield vs are you sure this works? this will block the cpu to max usage, so even the timer wont be take in consideration: speed_counter will be 0 forever. IMO. Think i tried it the first time. |
|
jamal
Member #3,326
March 2003
|
Quote: Nunca Ese said: jamal said: while (speed_counter > 0) { If computer is slow at a certain moment speed_counter will grow a lot. If cpu gets free later, cpu will try to do this amount of counter that couldn't do, so you will have a really fast moment on the game. (Dont know if i have explained it well; i mean, that you have to control lost frames in a moment, and no extend them to later; if so, later will have more than 60fps, what can be a bad effect for animations). I know about this but I don't think it's a good solution to have the logic and the drawing dependant. Imagine you have a computer playing your game at 30 fps. Another computer will play it at 60 fps (which is what you want). if logic and drawing are dependant, the game will be two times slower in the first computer ( I mean here the moving of characters,...), so this won't be the same game. In the other hand ("my way") the game will always be the same, exept a bad drawing if the computer is too slow. Quote:
Nunca Ese said : are you sure this works? this will block the cpu to max usage, so even the timer wont be take in consideration: speed_counter will be 0 forever. IMO. Think i tried it the first time. I don't think so because the incrementation of speed_counter is done via a thread so is independant of the main loop [EDIT] *lock the FPS* means do nothing as I corrected it the second post [/EDIT] |
|
tobing
Member #5,213
November 2004
|
The timer precision is given by a certain constant (forgot the name in the moment), and back in Windows 3.1 the accuracy of a timer was very low, something like 18 updates with a second or so. All that has improved, so the timer accuracy should be at least 0.1ms if not better (Windows XP, I do not know about any of the other systems). I have never used any other function than rest() resp. Sleep() to give time back to the cpu, so I don't know any of the other functions mentioned above - timeBeginPeriod() or yield_timeslice(). This form of waiting: while(speed_counter == 0){/*lock the FPS*/} is something I do not like, because it uses 100% cpu to do just nothing. It is not nice, and uses a lot of resources on a notebook, which I believe it shouldn't. So I would use something like while(speed_counter == 0){rest(1);} to wait without wasting resources like cpu usage. |
|
Nunca Ese
Member #5,262
November 2004
|
jamal said: Imagine you have a computer playing your game at 30 fps. Another computer will play it at 60 fps (which is what you want). if logic and drawing are dependant, the game will be two times slower in the first computer
This only happens if computer is too slow, which is the same performance in your case. Its normal that it will be two times slower, thats in the case that cpu and video card do the stuff at half the speed from the minimum requirements. jamal said: In the other hand ("my way") the game will always be the same, exept a bad drawing if the computer is too slow. Hope the comment above applies to this sentence. Mine will have reduced performance only if it cannot draw 60fps, which is equal to "slow computer". What i mean is that its better using speed_counter = 0; instead of speed_counter--; if you are not going to consider the lost frames. If computer is slow at a certain moment (54 fps): The other point is a behaviour for the 6 frames (look at the javier arevalos' article (link some messages above), there they have a good way to control (using interpolation) the lost frames): // Easy but not very useful way if(speed_counter > 0) { speed_counter--; // losts while(speed_counter > 0) { // frame lost, do X speed_counter--; } }
tobing said: I have never used any other function than rest() resp. Sleep() to give time back to the cpu, so I don't know any of the other functions mentioned above - timeBeginPeriod() or yield_timeslice().
Neither Maybe the problem with rest is: void rest(unsigned int time); This function waits for the specified number of milliseconds. Passing 0 as parameter will not wait, but just yield. This can be useful in order to "play nice" with other processes. Other values will cause CPU time to be dropped on most platforms. This will look better to users, and also does things like saving battery power and making fans less noisy. Note that calling this inside your active game loop is a bad idea, as you never know when the OS will give you the CPU back, so you could end up missing the vertical retrace and skipping frames. On the other hand, on multitasking operating systems it is good form to give up the CPU for a while if you will not be using it. |
|
Evert
Member #794
November 2000
|
Quote: Its normal that it will be two times slower, thats in the case that cpu and video card do the stuff at half the speed from the minimum requirements.
Having your game run at half the speed it is meant to run because the computer can't draw all frames is poor design. It's more important that the logic runs at a constant rate on all computers (in sofar as that is possible) than that you don't skip animation frames because otherwise the animation will be less smooth. Quote:
Neither Did you remember to declare speed_counter as volatile? Quote: The problem is that timeslice size changes from so version, so its like rest(variable) IMO. I'm not sure what you mean? Quote: Note that calling this inside your active game loop is a bad idea, as you never know when the OS will give you the CPU back, so you could end up missing the vertical retrace and skipping frames.
Look at the code. They're not calling it from the active (meaning logic) loop. |
|
FMC
Member #4,431
March 2004
|
jamal said: I don't see why use Rest would resolve the problem because, regardless of I never said to use rest to keep framerate constant; what i was suggesting was to use yield_timeslice to play nice with multitasking. Since in a previous allegro WIP there was a bug that didn't make yield_timeslice work under windows, Marco introduced rest, but only as a mean to yield, not for fps. [FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites] |
|
tobing
Member #5,213
November 2004
|
This is my game loop as I use it currently:
including performance measurements. The basic structure is from the german book I had recommended some days ago, the important things I added are rest() and performance measure. Feel free to comment on this code, I would be glad to improve it where I can. |
|
jamal
Member #3,326
March 2003
|
Quote:
Mithrandir said :
sorry Mithrandir I misunderstood you Nunca Ese : |
|
Matt Smith
Member #783
November 2000
|
Quote: Isn't better to let all the logic update at 60 fps and render at the best speed the computer can? I think human eye can still feel the difference between 60fps and 75fps, so if I can run at 75fps why not? One reason why not is beat frequencies. Your example would give an artifact at 15 Hz, which is acceptable IMO, but an extreme example would be logic at 60Hz with display at 61Hz, which in a slow scroll would produce a visible jerkiness at 1Hz intevals. Other less obvious artifacts can cause trouble at the epilepsy-inducing frequencies (around 3-7Hz) which are uncomfortable for most viewers. The best policy would probably be to allow only certain fixed frequencies for displaying. You could even make it explicit by coding each display freq as follows (this is for the 4:5 relationship of 60 and 75Hz) loop:update_logic(); update_screen(); //with vsync update_logic(); update_screen(); update_logic(); update_screen(); update_logic(); update_screen(); update_screen(); jmp loop
|
|
|
|