Window Main Loop - oli-obk/gosu GitHub Wiki
Usually, you create a subclass of Gosu::Window
and override the parts that you need. Then, you create an instance of this class and call show
on it. What happens then is this:
Examples of what you can do in these events are shown on the Ruby Tutorial and C++ Tutorial pages.
There are details that you may be interested in:
-
draw
is very flexible. The usual flow is shown above, butdraw
is generally called whenever the OS wants to redraw the window. This may be directly upon callingshow
, or even twice betweenupdate
calls, or not at all during a frame if the window is obscured. - It follows that you cannot know at all which callback will be called first.
initialize
(or the constructor in C++) must set up a valid state. If update containsif player == nil then respawn()
, theninitialize
should also containrespawn()
. You can just callupdate()
as the last call ininitialize
/the constructor if it helps. - Because
draw
is so flexible, it should really only render the current state of things and not change anything, not even advance animations. If you writedraw
in a functional, read-only style then you are safe. - In
update
, you may want to checkbutton_down?
(orinput().down()
in C++) to poll the most recent state of a button. Because the input events should logically be fired beforebutton_down?
is updated, it follows that they all have to happen beforeupdate
. This sadly means that you cannot directly react to the very latest button events indraw
; anupdate
call will always happen inbetween. - Because
TextInput
may call back into the game (filter
callback), it is not buffered and can happen at any place during the loop. You cannot rely ontext()
being the same betweenupdate
anddraw
either. - Don't be scared though, nothing in Gosu is multi-threaded and no callback is ever interrupted for another!
What if the system is too slow to run the game at its intended framerate? There are two major solutions.
First, you can write your game logic in the style of the example games. In every logical frame (update
), the player moves by a fixed amount of pixels forward. Animations also advance with every logical frame etc. This will result in rather integer-based, discrete game code. The CPU may like it too, especially in Ruby or on ARM processors.
However, if the system is too slow for your game, you are very limited in your options:
- You can spawn less particles or reduce eye candy in other ways. This only works if there is much eye candy to begin with.
- You can drop frames by returning false in the
needs_redraw?
/needsRedraw()
callback. You have to be careful not too skip too many frames in a row though.
You can also write your games by checking Gosu::milliseconds()
between one update
call and another, then update your game state based on the time different (delta time, dt). This allows physics to be written in a style that matches school physics (position += speed*dt) and is very common when working with physics engines.
This style naturally works better with a low framerate, but may need more up-front thinking, and the calculations may be slower in general because floating-point values are a more natural fit here.
This is definitely a by-case choice and Gosu tries to support both styles of programming.