Optimization using Servers

    There are, of course, always drawbacks:

    • Performance is lower than using simple APIs directly
    • It is not possible to use multiple threads to control them
    • More memory is needed.

    In many cases, this is not really a problem (Godot is very optimized, and most operations are handled with signals, so no polling is required). Still, sometimes it can be. For example, dealing with tens of thousands of instances for something that needs to be processed every frame can be a bottleneck.

    This type of situation makes programmers regret they are using a game engine and wish they could go back to a more handcrafted, low level implementation of game code.

    Still, Godot is designed to work around this problem.

    One of the most interesting design decisions for Godot, is the fact that the whole scene system is optional. While it is not currently possible to compile it out, it can be completely bypassed.

    At the core, Godot uses the concept of Servers. They are very low level APIs to control rendering, physics, sound, etc. The scene system is built on top of them and uses them directly. The most common servers are:

    • : handles everything related to graphics.
    • PhysicsServer: handles everything related to 3D physics.
    • : handles everything related to 2D physics.

    Just explore their APIs and you will realize that the all functions provided are low-level implementations of everything Godot allows you to do.

    RIDs

    Most Godot nodes and resources contain these RIDs from the servers internally, and they can be obtained with different functions. In fact, anything that inherits Resource can be directly casted to an RID (not all resources contain an RID, though, in such cases the RID will be empty). In fact, resources can be passed to server APIs as RIDs. Just make sure to keep references to the resources outside the server, because if the resource is erased, the internal RID is erased too.

    For nodes, there are many functions available:

    • For CanvasItem, the method will return the canvas item RID in the server.
    • For CanvasLayer, the CanvasLayer.get_canvas() method will return the canvas RID in the server.
    • For Viewport, the method will return the viewport RID in the server.
    • For 3D, the World resource (obtainable in the and Spatial nodes) contains functions to get the VisualServer Scenario, and the PhysicsServer Space. This allows creating 3D objects directly with the server API and using them.
    • For 2D, the resource (obtainable in the Viewport and nodes) contains functions to get the VisualServer Canvas, and the Physics2DServer Space. This allows creating 2D objects directly with the server API and using them.
    • The VisualInstance class, allows getting the scenario instance and instance base via the and VisualInstance.get_base() respectively.

    Just explore the nodes and resources you are familiar with and find the functions to obtain the server RIDs.

    It is not advised to control RIDs from objects that already have a node associated. Instead, server functions should always be used for creating and controlling new ones and interacting with the existing ones.

    This is a simple example of how to create a sprite from code and move it using the low-level API.

    GDScript

    The Canvas Item API in the server allows you to add draw primitives to it. Once added, they can’t be modified. The Item needs to be cleared and the primitives re-added (this is not the case for setting the transform, which can be done as many times as desired).

    GDScript

    Instantiating a Mesh into 3D space

    The 3D APIs are different from the 2D ones, so the instantiation API must be used.

    GDScript

    This creates a RigidBody2D using the API, and moves a CanvasItem when the body moves.

    GDScript

    The 3D version should be very similar, as 2D and 3D physics servers are identical (using and PhysicsServer respectively).

    Getting data from the servers

    Try to never request any information from , or by calling functions unless you know what you are doing. These servers will often run asynchronously for performance and calling any function that returns a value will stall them and force them to process anything pending until the function is actually called. This will severely decrease performance if you call them every frame (and it won’t be obvious why).