Update loops, physics and render. [Touch of Technical]
[h2]Doing side quests[/h2][p]This will be long![/p][p]A few weeks ago I started working a bit on the next version of the "engine" I have been using for making A Ruthless World (ARW). I got it rolling by branching the engine in git and starting a new project by copying ARW and minimizing it down to a barebones project that goes through boot->menus->level01->level02.[/p][p]Interestingly when going over and minimizing what was included I found all sorts of small bits and pieces to fix/improve and now have a good list of things I can later move over to the old engine as well, improving the upcoming release of ARW.[/p][p][/p][h2]Getting stuck in a time loop[/h2][p]A main area of interest was reviewing and trying to improve the game update loop. This is the loop that runs with physics, game logic and render updates.[/p][p]The current version runs using a requestAnimationFrame, which is the standard approach to running a loop that needs to sync nicely with the browser drawing. There are a few issues however with this when doing a game, in particular if using physics.[/p][p]requestAnimationFrame will always try to run at the refresh rate of the screen, meaning it can vary from the historically standard rate of 60Hz, to the more modern rates of everything from 90Hz, to 240Hz and above![/p][p]For the regular game logic loop this is all good, the faster the refresh rate the smoother and more responsive the game will become. To deal with the difference in update rates you solve it by using a delta value. Where everything happening over time is multiplied with the delta to make the end result the same, regardless of refresh rate. Example: If 60Hz is a delta of 1, then 120Hz will result in a delta of 0.5. As the update will not run exactly at the refresh rate, this delta varies a little bit for each update.[/p][p]The delta gives a predictable result over time as at a high fresh rate, each update will do less, and at a lower refresh rate each update will do more, making the change happening during a set amount of time be the same.[/p][p]For physics however this does not work so well. While the overall result will be somewhat the same, physics behave differently based on how often they are updated, regardless of the use of a delta. To solve this you create a fixed time loop, that runs at an as precise rate as possible. This is where using the requestAnimationFrame can be a bit problematic when doing physics and syncing physics positions/rotations to visual graphics position and rotation.[/p][p][/p][h2]Physics considerations[/h2][p]If the physics update at 60Hz, then all will be good if the screen refresh rate is 60Hz as well. Physics update, game logic updates position of graphics based on the physics data, render draws the graphics when the screen refreshes. All in sync and rendered smoothly.[/p][p]But already here there will be a small issue. As the physics will have a loop that tries to run at exactly 60Hz, but actual timing of each update will vary slightly, every now and then the physics will either wait one update or do two updates in a game update to keep that fixed update timing. This can cause some stuttering in the render as physics and game logic updates are no longer exactly in sync. This can be fixed, more on that later.[/p][p]A second issue will be that if the screen is running at a higher refresh rate, say 120Hz, then the game logic update and render will update 120 times a second, but the physics using the fixed rate, will only update 60 times a second. This results in no visual difference for everything using physics, as it will simply be drawn in the same way twice![/p][p]You can't simply fix this by also running physics at 120Hz if the screen is capable of 120Hz, because then the physics will behave differently and you can not predict what will happen for those users. Hence you have to pick a fixed physics update rate and stick with it.[/p][p][/p][h2]Old solution and initial improvements[/h2][p]My old solution was to run the physics at 120Hz, this because the games I make are not that resource hungry and as long as I can run the game at 60Hz on my almost 10 year old iPad I'm within the window of what I want to support.[/p][p]The old solution was:[/p]
- [p]Game update that runs with a requestAnimationFrame.[/p]
- [p]Physics updates first at 120Hz.[/p]
- [p]Game logic updates at screen refresh rate.[/p]
- [p]Game renders at screen refresh rate.[/p][p][/p]
Three out of seven different controllers used while testing.

Xbox gamepad to the left, PS gamepad to the right.