Creating a Godot Engine-based simulator

In this tutorial, we’ll use the Godot game engine to create a simple, not-so-fancy simulator that serves as a barebones boilerplate for Godot-based simulators prepared for distributed simulation using the Inhumate RTI.

You’ll create a simple “walking simulator” where the player can move around using W, A, S, and D, drop boxes, and interact with the physics engine. Not exactly an exciting player experience, but it is a straightforward way to structure the project to take advantage of Inhumate Suite features. The simulator will support recording, playback, co-simulation (multiplayer), and much more.

Setup the project

Create a new Godot project and prepare it with the Inhumate Godot integration package.

Note: This tutorial requires .NET SDK and the Godot Engine - .NET with C# support.

  1. Download the integration package from the Inhumate website

  2. Create and start a new project.

  3. Create a new folder in your res:// in FileSystem. Name it addons.

  4. Go to the AssetLib tab, click Import..., select the package zip file, change install folder to the addons folder, check Ignore asset root, and finally click Install.

  5. Verify that the package has been added in your filesystem.

  6. Project > Tools > C# > Create C# solution.

  7. Add required NuGet Package by doing one of the two:
    • Run this command in your project folder:
     dotnet add package Inhumate.RTI
    
    • Add this to your project’s .csproj file:
     <ItemGroup><PackageReference Include="Inhumate.RTI" Version="1.5.1" /><ItemGroup>
    
  8. Build project by pressing the hammer icon.

  9. Project Settings > Plugins tab > check Enabled

  10. Finally, reload the project and you’re ready to use the Inhumate integration package!

Create the environment

In this section, we’ll create a simple enclosed arena to serve as the playing field and an interactive box scene.

  1. Add a Node3D as the root, save the scene, and name it (optional) demo.
  2. Make a square “arena” by using either StaticBody3D combined with CollisionShape3D and MeshInstance3D, or multiple CSGBox3D with a CSGCombiner3D. Enable collision. See image below for reference.
  3. Add DirectionalLight3D.
  4. Create a Rigidbody cube scene with required nodes. Name it box. This scene will be used later.

    arena

You should now have a playable level scene.

Create the player

Next, we’ll set up the player and enable basic movement and spawning of boxes.

  1. Create a Rigidbody capsule scene and name it player. Add required nodes.
  2. In the Rigidbody node, set Mass and linear, angular Damp all to 10. Enable Angular X and Angular Z in PhysicsBody3D axis lock. This will make movement implementation easier.
  3. Add Camera3D as a child. This will be your point of view when playing. Adjust it to your liking.
  4. Make a simple player controller script that moves the player with W, A, S, and D and instantiate the cube scene by pressing B.

    Start by adding your members, and switch camera if you have multiple:

     @onready var camera = $Camera3D
    
     @export var box_scene: PackedScene
     @export var move_force: float = 1000.0
     @export var turn_torque: float = 50.0
     @export var spawn_distance: float = 3.0
    
     # Called when the node enters the scene tree for the first time.
     func _ready() -> void:
         camera.make_current()
    

    Add the _physics_process() function and add your code for the player movement:

     func _physics_process(delta: float) -> void:
         var forward_input := 0.0
         var turn_input := 0.0
    
         # W / S movement
         if Input.is_key_pressed(KEY_W):
             forward_input += 1.0
         if Input.is_key_pressed(KEY_S):
             forward_input -= 1.0
    
         # A / D turning
         if Input.is_key_pressed(KEY_A):
             turn_input += 1.0
         if Input.is_key_pressed(KEY_D):
             turn_input -= 1.0
    
    
         # Forward/back force
         if forward_input != 0.0:
             var forward_dir = -transform.basis.z
             apply_central_force(forward_dir * forward_input * move_force)
    
         # Rotation torque
         if turn_input != 0.0:
             apply_torque(Vector3.UP * turn_input * turn_torque)
    

    And instantiate your box scene with _input():

     func _input(event: InputEvent) -> void:
         if event is InputEventKey and event.pressed and not event.echo:
             if event.keycode == KEY_B:
                 _spawn_box()
                
     func _spawn_box() -> void:
         if not box_scene:
             return
    
         var instance: Node3D = box_scene.instantiate()
         var forward = -global_transform.basis.z
         var spawn_pos = global_transform.origin + forward * spawn_distance
         get_tree().current_scene.add_child(instance)
         instance.set_deferred("global_position", spawn_pos)
    
  5. Attach the script and add your box scene in the inspector. Place the player and try playing the scene. Move around, drop boxes, and interact with them while being constrained by the arena.

At this point, the player, boxes, and arena are set up. You can now explore the basic features of the Inhumate Suite in this environment.

Add RTI nodes

Let’s add some nodes from our RTI Godot integration package and then look at the results in Inhumate Viewer.

Note: These nodes determine how scenes are represented in the Viewer and handled in the RTI. Feel free to change the values to suit your needs.

  • Add RTI Static Geometry node to the arena walls and floor.

  • Add RTI Entity and RTI Position nodes to the player scene. Set the Type and Size properties.

    entity_player position_player

  • Add RTI Entity and RTI Position nodes to the box scene. Set the Type and Size properties.

    entity_box position_box

Start Inhumate Viewer. When you run the project, you should see the player and the arena in the 3D tab in the viewer.

3d_viewer

Support runtime control and scenario loading

Now we’ll prepare the project for runtime control and scenario loading using the RTI by creating a new scene and some configuration.

  1. Create a scenario by right-clicking in your filesystem and creating a new resource. Search RTIScenario and click create.
  2. Open the scenario, name it, add your demo scene, and optionally add a description.

    scenario

  3. In your res:// folder, find and open rtisettings.tres.
  4. By default, Home Scene should be filled. If not, add the defaulthome.tscn scene from the package. Add your scene in the Scenarios property.

    rtisettings

  5. Change your Main Scene in project settings to defaulthome.tscn from the package.

Now, if you run the project, you should be able to select your scenario and press Load from the runtime control in Inhumate Viewer. Your demo scene has now loaded. Press Start and run around, spawn and interact with boxes and see the viewer mirror your actions. Try the other controls: Pause, Stop, and Reset.

Support playback and co-simulation

To support playback and co-simulation, the scene needs an RTI spawner that dynamically adds entities (the player and spawned boxes).

  1. Remove the player from your demo scene. Spawning will be handled by the RTI spawner.
  2. Create a copy of the player with the controller script excluded. Name it PlayerPlayback. This object will act as a “remote representation” during playback, ignoring any inputs.
  3. Create multiple empty Node3D (three is fine) and place them around the arena. These will act as spawn points.
  4. Add the RTISpawner node to your demo scene.
  5. In the spawner node, add the box and player playback scenes in Spawnable Entities with their respective types.
  6. Specify the player scene and add the player spawn points.

    spawner

With this setup, you are ready to test playback and co-simulation using Inhumate Recorder.

  • Load a scenario, press Start, play for a bit, then press Stop followed by Play.
  • Replay earlier recordings using the three dots menu and selecting Play.
  • Run another instance of the project to test co-simulation and verify you can see the other player.

Conclusion

You have now completed the basic setup for integrating the Inhumate Suite with a Godot project. Playback and co-simulation should be working, and you are ready to continue experimenting with additional features and configurations.


Copyright © Inhumate AB 2026