UnigineEditor
Interface Overview
Assets Workflow
Settings and Preferences
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Landscape Tool
Using Editor Tools for Specific Tasks
FAQ
Программирование
Setting Up Development Environment
Usage Examples
UnigineScript
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
CIGI Client Plugin
Rendering-Related Classes

Where to Put Your Code: Update(), Flush() or Render()

The world script has a number of functions that are used to code logic of the application. Initialization function of the world script (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 script execution to avoid memory leaks.

But what about the frame-by-frame update? In the world script there are three blocks for that:

  • in update() you can control what to render onto the screen and how to do it
  • in flush() you can simulate physics, perform calculations and implement non-rendering game logic
  • in render() you can correct behavior according to the updated node states in the same frame

Code Update()

In the world script update() you can specify all functions you want to be called every frame while your application executes. It serves for implementing rendering logic. In brief, everything graphics-related is to be controlled from withinupdate(). Here you can:

Notice
Do not apply forces and torques to rigid bodies in the update(). Otherwise, you will get unstable result that varies with each rendering frame.

World Callbacks

Callbacks set in the update() (for example, by using WorldTrigger or widget callbacks) are not executed immediately. They will be run only 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()

Using flush() function of the world script you can control physics in your application:

But do not hurry to code everything else in the update(). flush() can be used not only for physics simulation, but also to implement logic and perform calculations you would not want to do each and every rendering frame. Let us look into the details why is it so.

Usually, the physics framerate is lower than a rendering one (see the details), which makes flush() more performance-friendly in case of heavy calculations. It goes in parallel with rendering, so CPU bottleneck is avoided. Besides that, we know exactly how long one physics tick takes, because physics has a fixed framerate. These factors combined make flush() ideal to perform calculations.

For example, we need to calculate a new position for the object. We can do it in the update(), but it would stall the rendering. Instead, we can start rendering and in parallel calculate a new position using flush(). The problem that rendering frames are more frequent is easily solved. Knowing the new position, we can linear interpolate positions in between and apply them to objects each rendering frame. As a result, performance load will be much better balanced, without load peaks.

Notice
There are some limitations, however, for what can be done from within flush(). You can not:
  • Make reposition and transform nodes if they are enabled.
  • Create new nodes.
  • Delete nodes.
These operations can violate the started rendering process. As a workaround, in the flush() you can generate an array of nodes to be created, while actually create them in the update().

Physics Callbacks

Just like in case with update(), if you set any physics-based callbacks in the flush() or use 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, they are executed before the next flush(); if not, before the next world script update().

If you want to reposition or transform, create or delete nodes that are returned by your physics callback, the workflow is the same: store them in the array and then perform all necessary operations in update().

Code Render()

The render() function of the world script 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 hold in the hand, because the animation is actually played right after the world scriptupdate() has been executed. This means, returned bone transformations in the update() will be for the previous frame. World script render() is executed after animation is played, which means from within this function you can get updated bone transformations for the current frame and set them to the sword.

Notice
Use render() for correction purposes only; otherwise, this will increase the main loop time. All other functions should be placed within update() orflush().
Last update: 04.06.2018