The Core Game Loop

Updated: 11th January 2018 by Richard Davey   @photonstorm

When Phaser boots it creates an instance of Phaser.Game (src/boot/Game.js). This takes a Game Configuration object, which is passed to the Config handler (src/boot/Config.js), and all the various things it needs are extracted from it.

The Game object, unlike in V2, now only has a small number of properties and functions. It only looks after truly global systems, of which there are (currently) only 3: The Request Animation Frame handler, the Texture Manager, the Scene Manager and the Device class.

When the DOM Content Loaded event happens, the Game calls Game.boot. This sets-up the RNG, header, renderer, Scene Manager and starts RAF running.

A single tick

Every time RAF ticks it calls the following (in order)

  1. Game.step is called, which calls ...
  2. Game.mainloop.step which checks frame rate, updates delta values, etc
  3. This calls Scene.sys.begin once for all active Scenes
  4. This iterates all Scene.children, and calls preUpdate if they exist
  5. While the frame delta is within range it calls Scene.sys.update
  6. It then calls Scene.update (dev level callback)
  7. When the loop exits (because the frameDelta is > the step size) it ..
  8. Renderer.preRender which resets the canvas, cls, then ...
  9. Calls Scene.sys.render on all active Scenes, which each calls ...
  10. Scene.sys.updates.start which processes the Update Managers list
  11. If the Scene is visible, it then calls Game.renderer.render, which ...
  12. Iterates through all children calling child.render on each one.
  13. It then calls Scene.sys.updates.stop - which stops the Update Manager
  14. Then calls Scene.render (dev level callback)
  15. Finally mainloop calls Renderer.postRender and resets the panic flags.

In a tree form it maps to the following:

+ Game.step
+ MainLoop.step
  |
  +- All Active Scenes:
  +- Scene.sys.begin (called once per active state)
     |
     +- Iterates Scene.children, if child exists, call child.preUpdate
  +- While (frameDelta within step range)
     |
     +- Scene.sys.update
     +- Scene.update
  |
  +- Renderer.preRender
  +- 
  +- Scene.sys.render
  +- Update Manager Start (Scene.sys.updates)
  +- Game.renderer.render (if Scene is visible)
     |
     +- Renderer set-up (blend mode, clear canvas, etc)
     +- Batch Manager Start
     +- SceneManager.renderChildren
        |
        +- Iterates all children, calling child.render on each
  |
  +- Update Manager Stop (Scene.sys.updates)
  +- Scene.sys.end (resets frame delta and panic flags)

The above is subject to change heavily! There are currently lots of empty function calls in there (State.sys.update for example), so we may well optimize this path considerably.

In essence though the concept is: Once per frame we update all the timing values, update the core systems, update the children, and repeat this until our step value is high enough, then we render everything.