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?
2-Installing more than one timer will slow the program too much?
2. I think timers are implemented in a thread, so they shouldn't slow down your system too much.
1.-
Define timer and time rate:
// 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:
| 1 | // Reset vars |
| 2 | unsigned int lastFrame = 0; |
| 3 | fpsTimer = 0; |
| 4 | |
| 5 | // Install timers |
| 6 | install_int_ex(SEC_FUNC, SEC_RATE); |
| 7 | install_int_ex(FPS_FUNC, FPS_RATE); |
| 8 | |
| 9 | bool run = true; |
| 10 | do { |
| 11 | |
| 12 | if(lastFrame < fpsTimer || lastFrame == UINT_MAX) { |
| 13 | lastFrame = fpsTimer; |
| 14 | |
| 15 | // STUFF (logic + render + input?) |
| 16 | run = do_stuff(); |
| 17 | |
| 18 | } |
| 19 | |
| 20 | yield_timeslice(); // Save CPU (timer need it) |
| 21 | |
| 22 | } while(run); |
| 23 | |
| 24 | // Remove timers |
| 25 | remove_int(SEC_FUNC); |
| 26 | remove_int(FPS_FUNC); |
| 27 | ... |
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 agree with umperio
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
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)
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.
---
rest(1) didnt work for me, so i moved to yield.
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.
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.
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 }
you can lock the fps this way :
| 1 | volatile int speed_counter = 0; |
| 2 | |
| 3 | void increment_speed_counter() |
| 4 | { |
| 5 | speed_counter++; |
| 6 | } |
| 7 | |
| 8 | END_OF_FUNCTION(increment_speed_counter) |
| 9 | |
| 10 | void play_the_game() |
| 11 | { |
| 12 | LOCK_VARIABLE(speed_counter); |
| 13 | LOCK_FUNCTION(increment_speed_counter); |
| 14 | |
| 15 | install_int_ex(increment_speed_counter, BPS_TO_TIMER(60)); |
| 16 | |
| 17 | while (!game_over) { |
| 18 | while (speed_counter > 0) { |
| 19 | update_game_logic(); |
| 20 | speed_counter--; |
| 21 | } |
| 22 | |
| 23 | update_display(); |
| 24 | // no need to begin a cycle logic drawing if speed_counter=0 |
| 25 | while(speed_counter == 0){/*lock the FPS*/} |
| 26 | } |
| 27 | } |
I didn't know about the yield_timeslice function, but don't understand what it does, so i will continue with this stuff instead
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().
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.
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.
I don't see why use Rest would resolve the problem because, regardless of
the computer speed, sometimes you'll have to rest 10 ms, sometimes 0, ...
I think the only thing you have to do is to look at if logic has to be implemented, so just do nothing while timer_counter==0
just add one line after the drawing should do the trick :
while (!game_over) { while (speed_counter > 0) { update_game_logic(); speed_counter--; } update_display(); while(speed_counter == 0){/*do nothing*/} }
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
}
Not the right way. You should use:
while(!key[KEY_ESC]) { if(lastFrame >= fpsTimer && lastFrame != UINT_MAX)) { lastFrame = fpsTimer; // stuff } yield_timeslice(); }
Explanation:
| 1 | // Dont stop till user press key_esc |
| 2 | while(!key[KEY_ESC]) { |
| 3 | // First time lastframe = 0 and fpstimer = 0 |
| 4 | // (60 ticks per second = fps rate you have set for the fpstimer) |
| 5 | // Every tick fpsTimer goes ++ |
| 6 | // so lastframe will be fpstimer - 1 |
| 7 | // in that case you enter the if sentence to do the stuff |
| 8 | // this situation takes place 60 times in a second, so you paint 60frames |
| 9 | // If computer is slow and cannot paint 60 frames, pending frames are discarded |
| 10 | // lastframe would be < fpstimer 'n' times (where n is the frames lost) |
| 11 | // the UINT_MAX condition is to avoid uint overflow (fpstimer would be 0 and |
| 12 | // lastframe would be equal to UINT_MAX, so the '<' condition wouldn't work |
| 13 | // So the condition must be to paint 60 times |
| 14 | if(lastFrame < fpsTimer && lastFrame != UINT_MAX)) { |
| 15 | lastFrame = fpsTimer; |
| 16 | // stuff |
| 17 | |
| 18 | } |
| 19 | // this is needed to prevent cpu from tax death |
| 20 | yield_timeslice(); |
| 21 | } |
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
You can use:
(lastframe < fpstimer) { lastframe = fpstimer; // stuff } or (fpstimer > 0) { fpstimer = 0; // stuff }
I think you can control time better using the first solution.
while (speed_counter > 0) {
update_game_logic();
speed_counter--;
}
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).
// yield vs
while(speed_counter == 0){/*lock the FPS*/}
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.
Nunca Ese said:
jamal said:
while (speed_counter > 0) {
update_game_logic();
speed_counter--;
}
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.
Nunca Ese said :
jamal said:
// yield vs
while(speed_counter == 0){/*lock the FPS*/}
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]
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.
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.
If computer is fast enough to run 60fps it will (thats the concept of minimum requirements).
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):
your code will do spped_counter to reach 6 (value) (60 ticks - 54 times)
When computer restores its normal speed your code will have speed_counter = 6, so next time it will try to do 66fps, what is not they right vehaviour (you want the computer to run 60fps all the time, not more than that).
6 frames is not a problem, but imagine the case that antivirus suddenly starts to scan (slow computer) or p2p running, or any kind of background program, (downloading tasks, etc.) that can make your game to lose 60 frames (this would make your game to try 120fps next second, animations at double speed). Frames sould be discarded, so speed_counter should be set to 0, losing the 6 frames.
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--; } }
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
- while(speed_counter == 0){/*lock the FPS*/}
nor
- while(speed_counter == 0){rest(1);}
worked for me. speed_counter was always 0 on the first case, and dont remember what, but bad behaviour with rest()
yield_timeslice() gives up the rest of the current scheduler timeslice. The problem is that timeslice size changes from so version, so its like rest(variable) IMO.
Maybe the problem with rest is:
***** start manual info
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.
****** end manual info
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 completely changes the dynamics of the game if what was a fast-paced jump'n run game suddenly runs at half speed. Imagine what would happen if you tried to run an RTS over a network where not all computers have the same speed.
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.
Neither
- while(speed_counter == 0){/*lock the FPS*/}
nor
- while(speed_counter == 0){rest(1);}
worked for me. speed_counter was always 0 on the first case
Did you remember to declare speed_counter as volatile?
The problem is that timeslice size changes from so version, so its like rest(variable) IMO.
I'm not sure what you mean?
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.
The way I do this myself is to run the logic until it is up to date, then draw a frame if that is nescessary, otherwise just yield/rest.
I don't see why use Rest would resolve the problem because, regardless of
the computer speed, sometimes you'll have to rest 10 ms, sometimes 0, ...
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.
This is my game loop as I use it currently:
| 1 | //---------------------------------------------------------------------------- |
| 2 | |
| 3 | static volatile int timer_counter = 0; // set to 60 times per second - desired fps |
| 4 | |
| 5 | static void timerCounterUpdater() |
| 6 | { |
| 7 | ++timer_counter; |
| 8 | } |
| 9 | |
| 10 | static volatile int fps_counter = 0; // set to 1 per second - count fps |
| 11 | |
| 12 | static void fpsCounterUpdater() |
| 13 | { |
| 14 | ++fps_counter; |
| 15 | } |
| 16 | |
| 17 | static volatile int perf_counter = 0; // set to 1000 per second - measure time used by a certain code fragment |
| 18 | |
| 19 | static void perfCounterUpdater() |
| 20 | { |
| 21 | ++perf_counter; |
| 22 | } |
| 23 | |
| 24 | //---------------------------------------------------------------------------- |
| 25 | |
| 26 | struct FPSInfo |
| 27 | { |
| 28 | int logic; |
| 29 | int displayed; |
| 30 | int iteration; |
| 31 | int advance_cputime; |
| 32 | int display_cputime; |
| 33 | int show_cputime; |
| 34 | int perf_counter_; |
| 35 | }; |
| 36 | |
| 37 | |
| 38 | //---------------------------------------------------------------------------- |
| 39 | |
| 40 | // frame counter |
| 41 | static FPSInfo cur = { 0, 0, 0, 0, 0, 0, 0 }; |
| 42 | static FPSInfo displayed = { 0, 0, 0, 0, 0, 0, 0 }; |
| 43 | |
| 44 | |
| 45 | |
| 46 | void GameLoop::loop() |
| 47 | { |
| 48 | while(true) |
| 49 | { |
| 50 | bool needsRefresh = false; |
| 51 | cur_skip = 0; |
| 52 | BITMAP*const draw_buffer = display_engine.draw_buffer(); // what I draw onto |
| 53 | while( timer_counter > 0 ) |
| 54 | { |
| 55 | if( key[KEY_ESC] ) |
| 56 | exit(0); |
| 57 | |
| 58 | // handle user input |
| 59 | |
| 60 | // Book keeping |
| 61 | ++cur.logic; |
| 62 | --timer_counter; |
| 63 | ++cur_skip; |
| 64 | cur.advance_cputime -= perf_counter; |
| 65 | advance_game_time(); // advance logic game time |
| 66 | cur.advance_cputime += perf_counter; |
| 67 | if( cur_skip >= max_skip ) // max_skip is constant, e.g. 3 - max 3 frames may be skipped before the logical fps goes down |
| 68 | { |
| 69 | timer_counter = 0; |
| 70 | break; |
| 71 | } |
| 72 | needsRefresh = true; |
| 73 | } |
| 74 | if( needsRefresh ) |
| 75 | { |
| 76 | cur.display_cputime -= perf_counter; |
| 77 | // draw screen |
| 78 | { |
| 79 | acquire_bitmap( draw_buffer ); |
| 80 | clear_bitmap( draw_buffer ); |
| 81 | // do the drawing here |
| 82 | release_bitmap( draw_buffer ); |
| 83 | } |
| 84 | cur.display_cputime += perf_counter; |
| 85 | |
| 86 | cur.show_cputime -= perf_counter; |
| 87 | // Display double_buffer |
| 88 | needsRefresh = false; |
| 89 | display_engine.display_draw_buffer(); |
| 90 | cur.displayed++; |
| 91 | cur.show_cputime += perf_counter; |
| 92 | } |
| 93 | else |
| 94 | { |
| 95 | if( rest_dur_ms > 0 ) |
| 96 | rest( rest_dur_ms ); // rest for given amount of milliseconds if non-zero |
| 97 | } |
| 98 | cur.iteration++; |
| 99 | if( fps_counter > 0 ) |
| 100 | { |
| 101 | displayed = cur; |
| 102 | displayed.perf_counter_ = perf_counter; |
| 103 | cur.logic = cur.iteration = cur.displayed = 0; |
| 104 | cur.advance_cputime = cur.display_cputime = cur.show_cputime = 0; |
| 105 | fps_counter = 0; |
| 106 | perf_counter = 0; |
| 107 | } |
| 108 | } |
| 109 | } |
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.
Mithrandir said :
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.
sorry Mithrandir I misunderstood you 
Nunca Ese :
I think Evert explained it well : Logic has to run at a constant rate on every computer.
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
It completely changes the dynamics of the game if what was a fast-paced jump'n run game suddenly runs at half speed. Imagine what would happen if you tried to run an RTS over a network where not all computers have the same speed.
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.
Agree. I was talking about my turn based game and also solo games.
When computer is fast enough, both mine and yours works perfectly.
When computer is too slow for the fps rate:
- mine: skips logic and frames -> slow game = entire timeline rendered
- yours: skip frames -> normal game = timeline complete, but only pieces of the timeline shown
Think mine option is better for turn based and solo games.
Did you remember to declare speed_counter as volatile?
could be, dunno.
The problem is that timeslice size changes from so version, so its like rest(variable) IMO.
I'm not sure what you mean?
1st so = os (sorry, spanish SO -> english OS (Operating System))
It should read as: "The problem is that timeslice size changes from O.S. version, so its like rest(variable) IMO." you will rest un uncertain time, you dont know timeslice size and how far you are from the end of the timeslice.
Look at the code. They're not calling it from the active (meaning logic) loop.
The way I do this myself is to run the logic until it is up to date, then draw a frame if that is nescessary, otherwise just yield/rest.
Dont see why 'active' means 'inside logic', explain please
I was talking about my turn based game and also solo games.
[...]Think mine option is better for turn based and solo games.
It could a viable alternative in those cases. I wouldn't say it's better.
I'd hate for spiffy special effects to take up too much of my time while playing a game, especially if I know they will not eat so much time when playing on a faster computer.
you will rest un uncertain time, you dont know timeslice size and how far you are from the end of the timeslice.
If your program is designed well enough, then you shouldn't care about this. As is said, rest(1) rests on average 1 ms.
Dont see why 'active' means 'inside logic', explain please
Nothing to explain, really. That's just what the docs mean by active.
It could a viable alternative in those cases. I wouldn't say it's better.
Yea, depends on who consumes the time, render or logic, and what you want to show.
you will rest un uncertain time, you dont know timeslice size and how far you are from the end of the timeslice.
If your program is designed well enough, then you shouldn't care about this. As is said, rest(1) rests on average 1 ms.
Agree. Im using yield_timeslace.
Dont see why 'active' means 'inside logic', explain please
Nothing to explain, really. That's just what the docs mean by active.
Ok. My mistake then.
Nice thread by the way!
The official guide to the use of Allegro timers.
Timers
It's far from complete, please improve it if you have things to add or correct.
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
Actually that's the big problem with hardcoding the ticks per second in the game. Playing a game coded at 60fps on a 85Hz display mode looks very jerky (this is most noticeable in 3D games or 2D games with fast scrolling). One solution is to force display frequency, but not all video drivers allow it, or the user may have disallowed it, so it's not a perfect solution.
That's why most comercial games use a variable timing interval (they check how much time has passed since the last logic, using WinAPI's GetPerformanceTimer()). I haven't tried this method yet, but I'll certainly do. The general algorithm to move an object this way would be something like this:
| 1 | myGame() |
| 2 | { |
| 3 | while(!end) |
| 4 | { |
| 5 | do_logic(); |
| 6 | draw_stuff(); |
| 7 | } |
| 8 | } |
| 9 | |
| 10 | int last_update = 0; |
| 11 | do_logic() |
| 12 | { |
| 13 | int cur_time = CurrentTime(); |
| 14 | int ellapsed_time = cur_time - last_update; |
| 15 | |
| 16 | ball_position_x += speed * ellapsed_time; |
| 17 | |
| 18 | last_update = cur_time(); |
| 19 | } |
I suggested rest(1), but probably I should have said rest(0). Right now I think the latter is the correct. IIRC there was a bug somewhere about yield_timeslice() and people suggested me to use rest(), probably with 0, not with 1.
Using 0, IIRC will release the timeslice, without any wait.
Well I'm more confused now.
For example, to show a circle that change it color per loop.
If I want 60 different colors per second, how is the code?.
| 1 | volatile int timer = 0; |
| 2 | void timer_handle() { timer++; } END_FUNCION(timer_handle) |
| 3 | |
| 4 | int main() { |
| 5 | allegro_init(); |
| 6 | set_gfx_mode(GFX_AUTODETECT,680,400); |
| 7 | LOCK_VARIABLE(timer); |
| 8 | LOCK_FUNCTION(timer_handle); |
| 9 | install_int_ex(timer,BPS_TO_TIMER(60)) |
| 10 | |
| 11 | int color; |
| 12 | while(!key[KEY_ESC]) { |
| 13 | ??? |
| 14 | color++; |
| 15 | circle(screen,screen->w/2,screen->h/2,50,color); |
| 16 | } |
| 17 | } |
| 18 | END_OF_MAIN() |
| 1 | volatile int timer = 0; |
| 2 | void timer_handle() { timer++; } END_FUNCION(timer_handle) |
| 3 | |
| 4 | int main() { |
| 5 | if(allegro_init() != 0) exit(1); |
| 6 | if(set_gfx_mode(GFX_AUTODETECT,680,480,0,0) != 0) exit(1); |
| 7 | LOCK_VARIABLE(timer); |
| 8 | LOCK_FUNCTION(timer_handle); |
| 9 | install_int_ex(timer_handle,BPS_TO_TIMER(60)); |
| 10 | |
| 11 | unsigned int color = 0; |
| 12 | while(!key[KEY_ESC]) |
| 13 | if(timer) { |
| 14 | timer--; |
| 15 | color++; |
| 16 | circle(screen,screen->w/2,screen->h/2,50,color); |
| 17 | } |
| 18 | } |
| 19 | END_OF_MAIN() |
@ImLeftFooted
... if(timer) { timer-- // vs ++ ...

| 1 | volatile int timer = 0; |
| 2 | void timer_handle() { timer++; } END_OF_FUNCTION(timer_handle); |
| 3 | |
| 4 | #define RATE 1 |
| 5 | |
| 6 | int main(int argc, char* args[]) { |
| 7 | allegro_init(); |
| 8 | set_gfx_mode(GFX_AUTODETECT,640,480,0,0); // 640x480 , not 680x400 ;) |
| 9 | LOCK_VARIABLE(timer); |
| 10 | LOCK_FUNCTION(timer_handle); |
| 11 | install_int_ex(timer_handle,BPS_TO_TIMER(RATE)); |
| 12 | install_keyboard(); // Would key[] work without this? |
| 13 | |
| 14 | int color = 0; |
| 15 | while(!key[KEY_ESC]) { |
| 16 | if(timer > 0) { |
| 17 | color++; |
| 18 | circlefill(screen,screen->w/2,screen->h/2,50,color); |
| 19 | rectfill(screen, 10, 10, 50, 20, 0); |
| 20 | textprintf(screen, font, 10, 10, makecol(255,255,255), "Frame %d", color); |
| 21 | timer--; |
| 22 | } |
| 23 | rest(1); |
| 24 | } |
| 25 | return 0; |
| 26 | } |
| 27 | END_OF_MAIN(); |
This code works (some mistakes on lucaz code). Take it and play with RATE param (set to 60 or whatever u want).
Yeesssssssssssssss, I hope Ive understood the idea.
When 'timer' becomes <0 it inmediatly turns to 60 again?
Yeesssssssssssssss, I hope Ive understood the idea.
When 'timer' becomes <0 it inmediatly turns to 60 again?
Not exactly. Timers are events thrown 'n' times in a sec. Those 'n' times are also known as ticks. What the program is doing is firing 60 ticks per second.
Every tick (=every 16,6ms) you call timer++.
Every 'while' iteration is supposed to run faster than 16,6, so you get timer == 1 every 16ms, process it (thats if(timer) which means if(timer!=0)) and set timer to 0 again (timer--) inside the condition.
You wont enter the if(timer) condition again till a new tick is fired (and timer++ is done) -> you will enter it 60 times in a sec.
change
you will notice that timer is always 1.
thanks a lot people!
Why not? :S
Because the rendering is usually the most expensive (system-wise) in your program. You want it seperated out so you can skip it if you fall behind (ie. frame skipping). Even you absolutely have to draw for your logic to properly run (which is rare), you still don't need to draw to the screen (unless you're using direct dirty rectangles like Allegro's GUI). It also helps the CPU cache when you access larger buffers, since the CPU wouldn't have to try to cache the buffer everytime you draw something more after doing a bit more logic. As well, WIndows and X don't really like mixing drawing to VRAM and using other input functions at the same time.
read this - about timing
http://www.geisswerks.com/ryan/FAQS/timing.html
Average duration of Sleep(1)
Gemini: 10 ms (10 calls to Sleep(1) took exactly 100 ms)
Vaio: ~4 ms (10 calls to Sleep(1) took 35-45 ms)
HP: 10 ms (10 calls to Sleep(1) took exactly 100 ms)
---
timeBeginPeriod() solves the problem:
it lowers the granularity of Sleep() to whatever parameter you give it.
So if you're on windows 2000 and you call timeBeginPeriod(1) and then
Sleep(1), it will truly sleep for just 1 millisecond, rather than the
default 10!
So if you're on windows 2000 and you call timeBeginPeriod(1) and then Sleep(1), it will truly sleep for just 1 millisecond, rather than the default 10!
I bet it doesn't do a thing for CPU usage that way either.
Thx for this really interesting article.
I bet it doesn't do a thing for CPU usage that way either.
It does!
If it really works it should be added to Allegro...
Ok, this is one of the best threads I ever read.
I love you ALL!!
My code currently looks like this and it works very good!
| 1 | if (no_skip == 1) speed_counter = 1; |
| 2 | |
| 3 | while(exityn_game == 0) |
| 4 | { |
| 5 | |
| 6 | while (speed_counter > 0) |
| 7 | { |
| 8 | input(); |
| 9 | speed_counter--; |
| 10 | fps_counter++; |
| 11 | } |
| 12 | draw_map(); |
| 13 | |
| 14 | /* added this line after I read this topic */ |
| 15 | if (no_skip != 1) {while(speed_counter == 0){rest(1);}} |
| 16 | |
| 17 | } |
THX!
timeBeginPeriod() solves the problem:
it lowers the granularity of Sleep() to whatever parameter you give it.
So if you're on windows 2000 and you call timeBeginPeriod(1) and then
Sleep(1), it will truly sleep for just 1 millisecond, rather than the
default 10!
That's some interesting information 
Will definitely keep that in mind.
I bet it doesn't do a thing for CPU usage that way either.
Why wouldn't it?
Normally when there is nothing to update, your CPU uses all of it's time to check if there is a need to update, and loop back. It does it over and over again, because that's what the loop tells it to do. Which means millions of "if (x)" checks and looping mechanisms (actual amount depends on the computer).
If you're averaging a wait of 16ms (~60fps) in 1ms increments, you're only making a maximum 16 "if (x)" checks each logic update. So naturally you're using far less CPU time.
I wonder how much confused can I be!
If you're averaging a wait of 16ms (~60fps) in 1ms increments, you're only making a maximum 16 "if (x)" checks each logic update. So naturally you're using far less CPU time.
But something needs to constantly check if that 1ms time period has passed or not. The scheduler granularity in Windows is 10ms, so the process that does the Sleep checking will only run approximately once every 10ms (unless you give it a higher priority, which will cause it to take more CPU). To get more than that, you'd need to busy loop, which doesn't do anything for CPU usage.
More than that though, even if you can get more Sleep granularity while still sleeping the CPU, the efficiency of Sleep reducing CPU usage will deteriorate since it will have to return to the program and check if another frame is ready more often, before going back to sleep. It's like going to bed then waking up every hour to check if 8 hours have passed, or sleeping at least 8 hours and not waking up before you need to. A game with 100 logic frames per second (or less) will do just fine with a Sleep granularity of ~10ms.
I have done some experiments with timeBeginPeriod() and rest() and such. First, thanks to all for these really interesting infos.
So now I can understand my measurements much better, which relate internal CPU counter and the CPU usage indicated in the task manager. Now, using timeBeginPeriod(1) in the start of my program changes the confusing behaviour I saw before into some understandable behaviour now.
Well, I was forced to include winmm.dll and stuff into my main program, so I tried to move timeBeginPeriod() into the implementation of rest(). That was a good idea! Works perfectly well for my program, and also better than changing the main program only.
So how can I propose this change for consideration for the next allegro change?
Next I have again analysed the behaviour of dlg, which uses 100% CPU on doing nothing, but not all the time. I think I should write the results in an extra thread, but again I have two little changes to propose here, one for allegro and one for dlg. How do I do that?
So how can I propose this change for consideration for the next allegro change?
You can send a patch (or post manually how the code should be changed) on the mailinglist, this forum, or through private message/email to one of the developers.
Thanks. I think I'll post the instructions how to change based on 4.1.17 into a new thread this evening. Same for dlg.
This may be useful too
That look a bit similar to what I'm doing in my game loop (which I posted in some thread last week, forgot which it was). Essentially I call rest(1) if I have some time to waste. As for the fps, I only want about 60fps (or another number, as this is configurable), I don't care for the very exact number here as long as it is about the requested number in the long run.
Have you tested timeBeginPeriod() in your gameloop?
FPS should get more accurate, but what about the CPU time (better or worse)?
Or are you using Linux?
I'm using Windows XP, and the fps got more accurate. Actually, that's not the whole truth. The code is using timers to control the loop. One timer is at 60/sec, one is at 1/sec to count the actual frame rate, and I use a third timer at 10000/sec to measure times of code sections at 0.1ms precision. The point was: If I use rest(1) within my game loop to give time back when I don't need that time for my current frame, I got different measures between my internal measurement and the task manager. Now that's pretty close, and overall cpu usage is reduced. Some secrets remain, though. Maybe I should report these in a separate thread, so you could try my latest executable (which is not online yet).
The code is using timers to control the loop.
Are you using Allegro's Timers? Because they are not accurate, you schould use QueryPerformanceCounter() to get exactly the fps you want. 
[edit]
and use the highest resolution possible - in ticks!
Yes, I'm using allegro's timers. I think that using timeBeginPeriod() and timeEndPeriod() also might increase precision of those timers.
Well, I might use any Windows specific functions, but that would mean I decide to not port the game to any other platform in future. Somehow I hesitate to make such a decision, so I would really prefer to stick to allegro's features.
Yes, I'm using allegro's timers. I think that using timeBeginPeriod() and timeEndPeriod() also might increase precision of those timers.
could be,
but resolution of 1ms isn't good enough, if you want fixed FPS and give CPU time back.
e.g.
You want to run your game at 60 FPS
Then one Frame schould take 16.6667 ms.
With allegro's timers you can get 16 or 17 (if timeBeginPeriod() increase precision on that timer)
if 16 then your FPS will be at 62.5
if 17 then your FPS will be at 58.8
The higher the FPS the less accurate the result.
Well, I might use any Windows specific functions, but that would mean I decide to not port the game to any other platform in future. Somehow I hesitate to make such a decision, so I would really prefer to stick to allegro's features.
I would write an timer class and use #ifdef _WIN32 for QueryPerformanceCounter() and timeBeginPeriod()
and #else for Linux. It has an High Resolution Timer too, something like getdaytime()?!
Actually I'm using allegro timers which call a function incrementing a variable at a given speed. I don't know that these are unprecise the way you suggest here, instead I found these timers quite reliable. So I have Timers working in a separate thread (I assume) and my game loop just looks at the values of the variables being incremented by these timers. So I can show the next frame when the variable becomes nonzero. Maybe my frames are not precisely 16.66666...ms apart, but in average they are, because some take 16ms where others would take 17ms.
OK +- 2 FPS is not that big deal for most games. 
How do you move objects? Is motion smooth? Do you use delta_time?
Cutrrently I'm not moving objects smoothly. Internally I distinuish between physical and logical time, because I want to be able to adjust the game speed in a wide range. So essentially this means that I put several logical frames into a physical frame (when game speed is high), and I can skip displaying physical frames also to avoid slowdown.
For later versions I want to implement smooth movement also, but currently I'm working on my A-Train clone (see depot) which did not have smooth movement in original, so I decided to do it the same way for the first version. Also I don't have animated sprites or tiles yet, that's also planned for the future.
What I am doing is:
I have a FPS (Frames Per Second) set to maximum 62 -> rest goes to CPU
and I have a LPS (Logic(Frames) Per Second) set to exactly 100
The FPS can drop as low as 1 Frame Per Second, but the Logic Per Second stays always at 100 (it takes 2 ms on my computer, while rendering takes ~9-11ms). I can spent ~3-4 ms pro Frame to the CPU, which is ~25% (depends on CPU).
I have a counter (64Bit) that counts the ticks since program start.
1 Tick = ~8.500.000 ms (If I remember correctly)
I do not use ms to calculate my movement, but ticks.
For that I have 2 helper function
long long ms2ticks(float ms);
float ticks2ms(long long ticks);
This way movement gets very precise on fast an also slow systems.
BTW the Logic is fixed to 100 updates because of my network code, which results in better ping times.
Sounds good.
Somehow I get the impression here, that almost everybody starting to program a game re-invents the game loop again and again. It might be a good idea to create a small collection of 'good' or 'state-of-the-art' game loops somewhere on this site, what do you think?
Anyway, I would like to see your game loop to learn how you do these things...
Somehow I get the impression here, that almost everybody starting to program a game re-invents the game loop again and again. It might be a good idea to create a small collection of 'good' or 'state-of-the-art' game loops somewhere on this site, what do you think?
this is a good idea
1) easy game loops - like the one in the faq - but not that accurate
can have more than one timer and use those for easy animation
2) synchron (fps = lps) needs delta or fixed speed
3) asynchron (fps <> lps) uses only one timer -
2 kinds of movement: pixels/logic or pixel/time
Anyway, I would like to see your game loop to learn how you do these things...
OK, kann ich später posten (da ich grad im Büro bin). Muss erst ein bissl suchen, da ich lange nicht mehr an dem Projekt gearbeitet habe, kaum Zeit gehabt...
Kein Problem.
und Dank im Voraus!
Edit:
The right place to collect game loops would be the Resources -> Code Gallery, which by now only has 3 entries.
OK, I found a gameloop, but this one is without my c++ timer class.
m2t() converts ms to ticks
t2m() converts ticks to ms
This was written a while ago - next step is port all to c++ and make code cleaner...
| 1 | void main_loop(void) |
| 2 | { |
| 3 | long long logic_delta; |
| 4 | long long render_delta; |
| 5 | |
| 6 | long long logic_wait = timer_ticks() + m2t(1000/LPS_wanted); |
| 7 | long long render_wait = timer_ticks() + m2t(1000/FPS_wanted); |
| 8 | |
| 9 | // game loop |
| 10 | while (isLoop) |
| 11 | { |
| 12 | // logic skip |
| 13 | logic_delta = logic_wait - timer_ticks(); |
| 14 | if (logic_delta < 0) |
| 15 | { |
| 16 | // calculate new logic_wait |
| 17 | logic_wait += m2t(1000/LPS_wanted); |
| 18 | |
| 19 | // update lps and gtpl |
| 20 | timer_update(LPS); |
| 21 | |
| 22 | // update logic |
| 23 | main_logic(); |
| 24 | } |
| 25 | |
| 26 | // render skip |
| 27 | render_delta = render_wait - timer_ticks(); |
| 28 | if (render_delta < 0) |
| 29 | { |
| 30 | // calculate new render_wait |
| 31 | render_wait += m2t(1000/FPS_wanted); |
| 32 | |
| 33 | // update fps |
| 34 | timer_update(FPS); |
| 35 | |
| 36 | // render frame |
| 37 | main_render(); |
| 38 | } |
| 39 | |
| 40 | // give os rest of cpu power & save battery |
| 41 | if (t2m(min(logic_delta, render_delta)) > 1) |
| 42 | { |
| 43 | // update sleep |
| 44 | timer_update(SLEEP); |
| 45 | |
| 46 | // CPU Sleep for 1 msec |
| 47 | Sleep(1); |
| 48 | } |
| 49 | } |
| 50 | } |
I have a FPS (Frames Per Second) set to maximum 62 -> rest goes to CPU
and I have a LPS (Logic(Frames) Per Second) set to exactly 100
Why are these different? Your logic rate should be the same as your max FPS (one logic update per frame, with frame dropping), or keep them in sync (FPS = LPS) using time deltas.
I want the network code (which is in a logic frame) highly responsive and I am scared of using threads. 
Using 100 Logic updates gives me way better results than 62 logic updates. But I don't want to render more often than 62/60 because it's a waste of CPU time. Ping is also getting better by using rest() / Sleep() , because RakNet is running in threads.