![]() |
|
Perfect Game Loop (A5 edition) |
SiegeLord
Member #7,827
October 2006
![]() |
So, since I recently decided to start playing around with A5, I again decided to tackle the problem of the perfect game loop for fixed timestep timing system (the only deterministic system there is). I've came up with two approaches, which roughly operate to give the same resulting logic per second and frame per second rates. This first approach uses A5 events and timers in a very hacky fashion. I don't really like it, although it takes the fewest number of lines, and perhaps is easier to understand. Basically, we use a timer only event queue to control our logic updates, and at the same time rest when possible.
The second approach takes more lines, but it does not use A5 timers or events, making it a little more elegant in that sense. It's operation is a little more complicated, but I am sure you all will be able to figure it out. Another advantage of this method is that it maps a little more closely to the abortive delta timing method, making it a little more tractable.
So yeah... comments/suggestions? I think the second one can be improved by hiding some of its functionality behind functions, for one. Notably, if you promise that your DoLogic() will never ever ever ever take longer than the fixed time step to complete, you can simplify the versions as follows: A5 Timer/Event:
A5 cur_time:
"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
Thomas Harte
Member #33
April 2000
![]() |
Quote: ... for fixed timestep timing system (the only deterministic system there is). Don't tell Newton! My only useful comment: if al_rest can at any point rest a little too short (e.g. if it resnts to within ±2ms) then following: al_rest(fixed_dt - dt); //rest at least fixed_dt dt = al_current_time() - old_time; dt may be less than fixed_dt. Is that what you want? If al_rest has a stated accuracy then you should round down to th enearest multiple of that and then add one more multiple, if it doesn't then I guess there's little you can do. Re: al_wait_for_vsync(); al_clear(black); DrawStuff(); al_flip_display(); Would it not be more sensible to do: al_clear(black); DrawStuff(); al_wait_for_vsync(); al_flip_display(); Vsyncing before your draw and then flipping after whatever portion of a frame it takes you to draw is likely to lead to tearing. Other than that, I've yet to fully digest the code. And it's slightly past work o'clock. [My site] [Tetrominoes] |
SiegeLord
Member #7,827
October 2006
![]() |
Aha, thanks for the vsync tip. It doesn't really work at all for me, so I couldn't tell the difference between different locations for it. Your reasoning makes sense though. Quote: Is that what you want? If al_rest has a stated accuracy then you should round down to th enearest multiple of that and then add one more multiple, if it doesn't then I guess there's little you can do. The idea is that we rest until the time passed since we last measured time is at least fixed_dt. dt is usually smaller than fixed_dt, so we usually rest for some period of time. "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
MiquelFire
Member #3,110
January 2003
![]() |
al_clear(black); I believe that should be in DrawStuff(); Maybe this was with AllegroGL (and by extension, OpenLayer) only (and I haven't looked at Allegro5's docs yet), but doesn't calling al_flip_display(); imply al_wait_for_vsync(); on platforms that support vsync? --- |
Trent Gamblin
Member #261
April 2000
![]() |
No, it doesn't.
|
Bob
Free Market Evangelist
September 2000
![]() |
Quote: doesn't calling al_flip_display(); imply al_wait_for_vsync(); on platforms that support vsync? It probably should (or at least be a parameter). It's not clear to me that al_wait_for_vsync() is useful by itself. -- |
Trent Gamblin
Member #261
April 2000
![]() |
How would it make any difference? The user calls al_wait_for_vsync then al_flip_display.
|
Bob
Free Market Evangelist
September 2000
![]() |
What happens if al_flip_display() waits for vsync anyway (eg: an OpenGL backend)? Do we wait for vsync twice? If we ignore al_wait_for_vsync() on those platforms, apps lose the ability to time things using vsync (which is still useful for many reasons). -- |
Trent Gamblin
Member #261
April 2000
![]() |
The opengl backend doesn't wait for vsync AFAIK unless you call al_wait_for_vsync yourself.
|
Bob
Free Market Evangelist
September 2000
![]() |
Yes it does. At the end of the day, it calls wglSwapBuffers(), which is allowed to (and most of the time does) wait for vsync, by default. -- |
Elias
Member #358
May 2000
|
We should remove al_wait_for_vsync and make it a display flag. -- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Quote: We should remove al_wait_for_vsync and make it a display flag. I was thinking the same thing. And a HINT at that. We can't guarantee its enabled or disabled since the user can force the issue in the driver settings. -- |
SiegeLord
Member #7,827
October 2006
![]() |
Okay, I looked around some other forums, and Bullet source code, and it seems that this is the optimal solution. I probably will put it up on the wiki eventually...
"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
Thomas Harte
Member #33
April 2000
![]() |
Sorry, this is absolutely more my day job editor instincts coming out than my programmer instincts, but maybe chuck an extra comment in above 'double start_time = al_current_time();' to the effect that the main logic call loop follows, so that it's more obvious to newbies where the section of code that "may need to be eliminated for networked games" ends? My unnecessary, tedious pedantry also makes me comment again on: SiegeLord said: fixed timestep timing system (the only deterministic system there is). To the effect that my argument for disagreeing with your assertion is that real life isn't run on a fixed timestep system and you cannot build a deterministic system from a non-deterministic system. [My site] [Tetrominoes] |
SiegeLord
Member #7,827
October 2006
![]() |
Quote: Sorry, this is absolutely more my day job editor instincts coming out than my programmer instincts, but maybe chuck an extra comment in above 'double start_time = al_current_time();' to the effect that the main logic call loop follows, so that it's more obvious to newbies where the section of code that "may need to be eliminated for networked games" ends? Ah, good point. I'll be more blatant about it, and why that actually works in the actual article. Quote: To the effect that my argument for disagreeing with your assertion is that real life isn't run on a fixed timestep system and you cannot build a deterministic system from a non-deterministic system. What I mean by deterministic is that, given identical starting conditions, when you run a game it will run identically in every case. This is impossible (pretty much) to do with a variable time step, especially one dependent on framerate. There are other benefits to using fixed step timing of course, but that's irrelevant in this case. "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
|