At which framerate Solarus runs ?

Started by MetalZelda, November 09, 2016, 01:11:52 AM

Previous topic - Next topic
This is an interesting question, we never got to face this question.

But, as I was reworking my time system script (yet again), I was wondering, should the time be incremented in on_update or in on_draw, pretty dull though you might say and these two functions update at almost the same rate (each screen refresh)

But, what is this ... refresh rate ...
Interestingly, I did a print(count) to see what amount we need before incrementing the minute counter, like so

Code (lua) Select

function menu:on_started()
  self.count = 0
end

function menu:on_draw(dst)
self.count = self.count + 1
end


self.count increases infinitely and would never end, so, I wanted to be sure about the formula 1 second in real life = 1 second in the game, depending on the time flow.
Setting the condition (if self.count >= 30) where 30 (might) be the framerate, something got wrong, the time flow rate is faster than expected
But, setting the limitation to 60 makes the time to go normal.

So, enlight me, I don't know much about framerate and stuffs, but if on_draw is called a each cycle (so each frame recheck) and if we need 60 refresh for the engine so 1 second irl = 1 minute in game,does this make Solarus to run at 60FPS ?
Also Dxtory, a screen recorder always display 60 as framerate when recording some stuffs

November 09, 2016, 01:54:07 AM #1 Last Edit: November 09, 2016, 01:57:00 AM by llamazing
Quote from: MetalZelda on November 09, 2016, 01:11:52 AM
I was wondering, should the time be incremented in on_update or in on_draw

You want to use a timer instead. Have it update every in-game minute, and then as an added bonus it will pause automatically during dialogs if you set the context to the map.

Do the increment in on_update, not in on_draw because some draws are skipped on slow machines.
The framerate is 50 fps.

Quote from: llamazing on November 09, 2016, 01:54:07 AM
Quote from: MetalZelda on November 09, 2016, 01:11:52 AM
I was wondering, should the time be incremented in on_update or in on_draw

You want to use a timer instead. Have it update every in-game minute, and then as an added bonus it will pause automatically during dialogs if you set the context to the map.

It is already a timer, but I wanna test other possibilities since there are functions made for updating stuffs

Quote from: Christopho on November 09, 2016, 08:07:54 AM
Do the increment in on_update, not in on_draw because some draws are skipped on slow machines.
The framerate is 50 fps.

So that's the difference between on_draw and on_update in term of updating and draw stuffs ?

November 09, 2016, 02:36:41 PM #4 Last Edit: November 09, 2016, 10:00:58 PM by Christopho
The main loop basically repeats update(), draw() (optionally) and sleep() (optionally). Each call to update() makes the simulated time advance of one fixed step.

And actually, the framerate is 100 fps for updates, not 50 fps.

update() is guaranteed to be called at each cycle, that is, 100 times per simulated second, which means every 10 simulated millisecond. Which also means that sol.main.get_elapsed_time() has been increased of 10 ms every time on_update() is called. update() updates the simulated world of one step: it moves entities according to their movement, checks user inputs, checks timers, checks collisions, etc.
Under normal conditions, the engine tries to keep the simulated time equal to the real time. So one update() call is done approximately every 10 real milliseconds. But if the main loop step takes too long for some reason (like a slow machine, a very heavy script, an engine bug or a specific frame that lasts more than 10 ms), the engine decides to skip some draw() operations so that updates are done quicker to try to keep up. And if the engine fails to do that, the simulated time can become slower than the real time. But in all cases, the simulation always remains deterministic, even on slow machines. on_update() calls are never skipped. Actually, the simulated time is by definition a counter incremented of 10 at every update(). Timers also only rely on simulated time, so like update(), they are reliable and give reproducible results.

Drawing operations, on the contrary, can be skipped by the engine sometimes in order to keep up. For this reason, you should never change any state in on_draw() events. Because they are not guaranteed to be called at the same simulated time on all machines. Basically, the engine decides to draw whenever it wants.

By the way, there are a few command-line flags to control the simulation loop:

- You can disable drawing completely with the flag -no-video. The simulation will still work. Unit tests do that.
- Try -turbo=yes to tell the engine not to wait for real time. The simulation time will pass as fast as possible (update() calls won't wait for real time). Unit tests also do that.
- Try -lag=50 (or any other value in ms) to add some delay to every frame. Useful to emulate a very slow system and check that your game still works under difficult conditions. You will notice that some drawing operations are skipped and the simulation might run slower.

See this great article for more information: http://gameprogrammingpatterns.com/game-loop.html
And the Solarus simulation loop code here (inspired from that article): https://github.com/solarus-games/solarus/blob/dev/src/MainLoop.cpp#L323

IMO, this post is one of the most interesting ones I have read in the forum. Maybe all this info should be somewhere in the Lua API (unless it already is there).
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Yes, very interesting post indeed, I now understand the difference between on_draw, on_update and their limitation