Unity Integration

Aside from basic RTI connectivity and publish/subscribe messaging, the Unity integration contains functionality for managing runtime control, entities, geometry, measures, injects, commands etc in a way that integrates nicely with the game engine architecture.

Getting started

See the Unity tutorial for setting up a new project and creating a basic simulator.

Adding the package

The Inhumate RTI integration for Unity is available in several locations depending on your preference:

Spawn co-simulated entities

Entities are objects/actors that exist in the co-simulation “world”, and their life cycle (create -> destroy) and state (more on that later) are synchronized via the RTI.

  1. Create a cube in your Demo scene hierarchy.
  2. Add an RTI Entity component, set its Type property to cube.
  3. Add an RTI Position component.
  4. Make it a prefab by dragging the cube from the Hierarchy view into your Project view.
  5. Delete the cube from the scene.
  6. Create an empty game object.
  7. Add an RTI Spawner component.
  8. For the Spawnable Entities property, add an element with type set to cube and drag your cube prefab into the prefab property.

Now, if you play the scene, you can spawn and destroy a cube using the RTI CLI:

# create a cube
rti entity create --id thecube cube 0 1 2.5
# look around and find it with the editor camera, then move it
rti entity position thecube 2 2 2.5
# then destroy it
rti entity destroy thecube

Spawn a player

Your scenario scene is loaded upon reception of a load scenario message. At that point, no entities should be created. You need to spawn the player when the simulation starts, not when the scene is loaded. You also need to either:

  • create a “remote representation” prefab that the RTI Spawner can use for playback, or
  • use the same prefab but adapt your scripts to differentiate between simulation and playback behavior. Use the RTIEntity.publishing and RTIEntity.receiving properties for that.

Custom (project-specific) messages

Now let’s start digging into adding more functionality than just runtime control, entities and their whereabouts.

Pubsub custom messages (string or JSON)

You can publish and subscribe to simple text or JSON messages.

RTIConnection.Instance.Publish("mychannel", "my message");
RTICOnnection.Instance.PublishJson("mychannel", mySerializableObject);

Pubsub protobuf messages representing entity state

A common pattern for Unity-based simulations is to exchange entity state beyond position, for example a vehicle that needs to publish its vehicle-specific state (e.g. steering angle and brake lights) so that it can be subscribed to and visualized by other simulation clients.

Let’s say you have a component Vehicle that manages your vehicle steering, lights etc.

Create a .proto with the protobuf definition of the state to be transferred:

syntax = "proto3";

message VehicleState {
    string id = 1; // entity id
    float steering_angle = 2; // degrees, positive right
    bool headlight = 3;
    bool brakelight = 4;
    bool blinker_left = 5;
    bool blinker_right = 6;
    bool reverselight = 7;
    // bool engine_running
    // int gear
    // int rpm
    // etc...
}

Use the protobuf compiler to generate a C# representation, typically placed in a Generated/ subfolder of your scripts.

Then make a component deriving from RTIEntityStateBehaviour, something along the lines of:

public class RTIVehicleState : RTIEntityStateBehaviour<VehicleState> {
   public string ChannelName => "vehiclestate";

   public float updateInterval = 1f;

   private Vehicle vehicle;

   protected override void Start() {
      base.Start();
      vehicle = GetComponent<Vehicle>();
   }

   void Update() {
      if (entity.published && publishing && Time.time - lastPublishTime > updateInterval) {
         lastPublishTime = Time.time;
         Publish(new VehicleState {
            Id = entity.id,
            SteeringAngle = vehicle.steeringAngle,
            Headlight = vehicle.headlight,
            // ...
         });
      }
   }

   protected override void OnMessage(VehicleState message) {
      if (receiving && enabled) {
         vehicle.steeringAngle = message.SteeringAngle;
         vehicle.headlight = message.Headlight;
         // ...
      }
   }
}

Scenario loading

Part of the runtime control standard message is a load scenario message, and querying for available scenarios. The default behavior of the Unity package is to load a home level on startup and stop message, and when a load scenario message is received, lookup the name in the scenarios list (which is populated with the scenes in build settings by default, or can be specified with Scenario objects in the editor) in the RTIConnection, and then load a scene with the same name as the scenario. This behavior can be overridden in a script that:

  • fills the RTIConnection.scenarios list with names of scenarios that can be loaded
  • implements delegates for RTIConnection.OnLoadScenario and RTIConnection.OnStop events

See RTITestCustomScenarioLoading.cs for an example.


Copyright © Inhumate AB 2026