Where to Put Your Code: Update(), Flush() or Render()
The world logic has a number of functions that are used to code logic of the application. Initialization function of the world logic (init()) is used to create objects and initialize all other necessary resources on the world load. Shutdown function (shutdown()) is called when the world is unloaded and is used to delete resources that were created during the logic execution to avoid memory leaks.
But what about the frame-by-frame update? In the world logic, this update is performed within the main loop that has three blocks for that:
- update() can contain any logic: control what to render on the screen and how to do it, render to textures, create nodes, call console commands, etc.
- flush() can be used to simulate physics: perform continuous operations (pushing a car forward depending on current motor's RPM, simulating a wind blowing constantly, perform immediate collision response, etc.).
- render() can be used to correct behavior according to the updated node states in the same frame.
Code Update()#
In the world logic update(), you can put all functions to be called every frame, while your application is executed. It serves for implementing any logic. In brief, you can control a lot of things (whether graphics-related or not) from within the update(). Here you can:
- Create and delete nodes.
- Move nodes around the scene and rotate them.
- Change any parameters of nodes.
- Simulate particle systems.
- Control skinned animation.
- Set global rendering settings.
- Create and manipulate your GUI.
- Render to textures.
- Execute console commands.
- Even do some physics — perform some momentary actions: add impulses, simulate a hit or a push, set linear or angular velocity, add or remove shapes and joints, and change their parameters.
World Callbacks#
Callbacks set in update() (for example, by using WorldTrigger or widget callbacks) are not executed immediately. They are run when the next engine function is called: that is, before flush(), if any (in the current frame), or before the next update() (in the following frame) — whatever comes first.
Code Flush()#
The flush() function of the world logic is used to control physics in your application. This function should be used for continuous operations such as pushing a car forward depending on current motor's RPM, simulating a wind blowing constantly, performing immediate collision response (as flush() can be executed several times during a single rendering frame, you can process multiple bounces of objects, when they collide with each other and monitor them, while the update() will only show us the final result), etc. So, in the flush() you can:
- Operate on all physical bodies and shapes.
- Apply forces, impulses, and torques to rigid bodies.
- Create, attach, or break joints, as well as modify their parameters.
- Create and manipulate shapes and modify their parameters.
- Create and adjust physicals.
- Reposition and transform nodes if they are enabled.
- Create new nodes.
- Delete nodes.
Physics Callbacks#
Just like in case with update(), if you set any physics-based callbacks in flush() or use a PhysicalTrigger, they cannot be executed immediately, as the rendering process is already in action and they can violate it. If there is one more physics iteration to go, these callbacks or a PhysicalTrigger are executed before the next flush(); if not, before the next world logic update().
If you want to reposition or transform, create or delete nodes that are returned by your physics callback, the workflow is as follows: store them in the array and then perform all necessary operations in the update().
Code Render()#
The render() function of the world logic is an additional function used to correct behavior after the state of the node has been updated (for example, skinned animation has been played in the current frame or particle system has spawn its particles).
Imagine a situation when we need to attach an object (let's say, a sword) to the hand of a skinned mesh character. If we get transformation of the character hand bone and set it to the sword in the update() function, the attachment will be loose rather than precise. The sword will not be tightly held in the hand, because the animation is actually played right after the world logic update() has been executed. This means, returned bone transformations in the update() will be for the previous frame. The world logic render() is executed after animation is played, which means you can get updated bone transformations for the current frame from within this function and set them to the sword.