|
VR-Engage
2.2
|
Purpose: This example implements a vehicle turn signal system to illustrate frontend-backend component coordination in VR-Engage. The implementation handles user input in the frontend, transmits commands through joystick messages to the simulation backend, and modifies entity state that propagates across the network.
Observable Behavior: Running this example produces keyboard-triggered blinker activation using ',' for left and '.' for right turn signals. The frontend component captures input and sends joystick messages to the backend actuator, which toggles blinker state and updates vehicle lighting. Visual dashboard indicators display blinker status through QML overlay bindings to entity state properties. Vehicle lighting state changes transmit automatically via DIS/HLA network protocols to remote visualizations.
Prerequisites:
Related Examples:
The vehicle blinker implementation covers frontend-backend component coordination by separating user interface concerns from simulation logic. The DtVehicleBlinkerControlLogic frontend component handles user input and UI integration, while the DtVehicleBlinkerActuator backend component modifies simulation state and vehicle lighting. This separation follows the standard VR-Engage architecture pattern where UI responsiveness remains independent of simulation tick rates.
Joystick message transmission provides the standard command mechanism between frontend and backend processes. The frontend converts input actions ("left-blinker", "right-blinker") to joystick messages that the backend routes via input ports to actuator logic. This messaging pattern decouples UI implementation from simulation logic while ensuring reliable command delivery across process boundaries.
The actuator component architecture extends VR-Forces with custom functionality through input ports that receive external commands. The implementation uses a toggle pattern where button presses invert current state, with state persistence maintained across simulation ticks through entity properties. This approach allows other components to access the blinker state for dependent functionality.
Vehicle state modification integrates with the networked simulation environment through the DtGroundVehicleLightingStateComponent. The QML dashboard overlay displays real-time blinker status via property bindings to entity state attributes. State changes transmit automatically via DIS/HLA to remote visualizations, ensuring consistent behavior across distributed simulation environments.
The vehicle blinker system consists of two plugins that coordinate through the VR-Engage messaging infrastructure. The frontend process handles user interaction and visual feedback, while the backend process manages simulation state and network propagation.
flowchart TB
subgraph Frontend["VR-Engage Frontend Process"]
Control["DtVehicleBlinkerControlLogic<br/>Captures keyboard input<br/>Maps to joystick message"]
Dashboard["QML Dashboard Overlay<br/>Shows blinker indicators<br/>Bound to state attributes"]
end
subgraph Backend["VR-Engage Backend Process<br/>(VR-Forces Simulation Engine)"]
Actuator["DtVehicleBlinkerActuator<br/>Receives via input ports<br/>Toggles blinker state<br/>Updates lighting state"]
Lighting["DtGroundVehicleLightingState<br/>Transmitted via DIS/HLA"]
Properties["Entity State Properties<br/>left-blinker-active<br/>right-blinker-active"]
Actuator --> Lighting
Actuator --> Properties
end
Control -->|"JoystickMessage<br/>(Network message)"| Actuator
Properties -.->|"State sync"| Dashboard
The frontend control logic handles keyboard input and converts user actions to standardized joystick messages. The backend actuator receives these commands, toggles persistent state properties, and updates vehicle lighting components. Visual feedback occurs through QML dashboard elements bound to entity state properties, providing real-time blinker status display. Network propagation transmits lighting state automatically to remote viewers via DIS/HLA protocols.
Message Flow: User input triggers a defined sequence of operations that spans frontend and backend processes. Keyboard presses (',' for left blinker, '.' for right blinker) activate input system actions that call DtVehicleBlinkerControlLogic::setLeftBlinker() or setRightBlinker() methods. The frontend sends JoystickMessage instances with function names "LeftBlinker" or "RightBlinker" to the backend process. The backend routes these messages to actuator input ports via the joystick controller system. The actuator toggles corresponding state properties (left-blinker-active or right-blinker-active) and updates the lighting state component. Dashboard QML overlay elements reflect state changes through property bindings, while DIS Entity State PDUs transmit the changes to remote viewers for synchronized indicator display.
The control logic handles input and converts to joystick messages:
The class inherits from DtEntityControlLogic, which provides the base vehicle control component functionality. The DtInputLogic member handles mapping input configuration to action handlers, while myMainJoystickGroup caches the joystick function group name used for message routing.
The initialization process establishes the connection between input configuration and handler methods. The component caches the first joystick group name from role configuration and sets up input logic for loading action-handler mappings. Input configuration loading requires the file specified in the role configuration and uses the "lights" input group to match keyboard.lua configuration.
The myInputConfigFile variable contains the filename from role configuration (vehicleBlinkerInput.lua), which defines key bindings that map ',' to "left-blinker" and '.' to "right-blinker" actions. The DtActionDelegate creates type-safe callback bindings to member functions. This design separates input binding configuration from handler logic implementation, enabling reconfiguration without code changes.
Action handlers convert input to backend commands:
The val parameter typically contains 1.0 for button press events and 0.0 for release events. The entity ID ensures the message routes to the correct backend entity, while the combination of function group and function name identifies the specific command. The message manager queues the message for transmission to the backend process.
The actuator receives commands and modifies state:
The DtBooleanInputPort members receive joystick message data routed from the frontend. The DtRwBoolean properties persist the blinker on/off state across simulation ticks, making them accessible to other components. Separate update methods for each blinker enable independent control of left and right indicators.
Input ports route joystick messages to the actuator:
The port names "left-blinker" and "right-blinker" must match the component descriptor configuration for proper message routing. The addInputPort() method registers each port with the actuator framework, enabling the joystick controller system to route messages by function name to the matching port.
Initialize retrieves persistent state properties:
The properties are defined in the component descriptor or entity configuration files. The nextFrameStateProperties() method accesses properties for the current simulation step, and these properties persist across ticks, making them readable by other components that need to query blinker status.
The tick method processes input port data and manages state transitions. The implementation checks for active connections and new data on each input port, acknowledging received messages and processing only button press events (ignoring releases).
The activeConnection() method confirms port connectivity to input sources, while newData() indicates message receipt since the last tick. The dataReceived() call acknowledges message processing and clears the new data flag. Toggle logic inverts current state on each button press, providing familiar turn signal behavior where repeated activation cycles the blinker on and off.
State update methods modify the networked lighting component to reflect blinker status changes. The implementation retrieves the ground vehicle lighting state component and updates indicator light flags based on current property values.
The DtGroundVehicleLightingStateComponent manages all vehicle lighting including headlights, brake lights, and indicators. The getNextFrameStateComponent<>() method retrieves the component for modification during the current simulation step. Lighting state changes transmit automatically via DIS Entity State PDUs, enabling remote visualization systems to render synchronized blinker indicators.
Plugin registration establishes component availability within the VR-Forces factory system. The backend plugin registers both actuator and descriptor components through the factory manager hierarchy.
The system definition file configures joystick controller and actuator components with their connections. The joystick controller defines function groups and individual controls, while the actuator provides input ports for receiving commands. Connection specifications link joystick output ports to actuator input ports.
System definition configuration requires both actuator and descriptor registration for proper component instantiation. The frontend uses DtPlayerStationApp::componentFactory() for UI components, while the backend uses DtCgf::factoryManager() for simulation components.
Build both components (see Environment Setup & Build Guide):
Install both plugins to the VR-Engage installation:
This copies:
<VR-Engage-Install-Dir>\plugins64\vrEngage\release\exampleVehicleBlinkerFrontend.dll<VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleVehicleBlinkerSim.dllVerify installation:
Plugin loading occurs automatically through the VR-Engage discovery system. Frontend plugins in plugins64/vrEngage/release/ load at startup without manifest configuration. Backend plugin configuration files install automatically through the VR-Engage toolkit installer.
Role configuration integration requires component specification in the driver role file. The configuration defines the control logic component with input file references and joystick function groups. Extended state logic configuration establishes the state properties that persist blinker status.
Input configuration maps keyboard keys to action names through device-specific mappings. The configuration uses the "lights" group to organize related input actions and specifies key-to-action bindings for left and right blinker controls.
Entity configuration includes the vehicle blinker system reference and establishes the driver role relationship. The system definition reference (vehicle-blinkers.sysdef) provides the joystick controller and actuator configuration, while the role specification links to the driver configuration file.
Verification:
Frontend plugin not loading:
<VR-Engage-Install-Dir>\plugins64\vrEngage\release\Backend plugin not loading:
<VR-Engage-Install-Dir>\plugins64\vrForces\release\Key press not triggering blinker: Input system failures typically result from configuration mismatches or missing action handler registration. The input configuration file (vehicleBlinkerInput.lua) must exist in the role configuration path, and the input group name "lights" must match between handler registration and keyboard.lua configuration. Key mapping verification requires confirming that ',' maps to "left-blinker" and '.' maps to "right-blinker" actions.
Blinker state not changing: State modification failures occur when entities lack required components or state properties. Ground vehicle entities (domain=1, kind=1) should include DtGroundVehicleLightingStateComponent automatically. State properties left-blinker-active and right-blinker-active require definition in role configuration through the extended state logic component.
Dashboard indicators not working: Visual feedback failures result from incorrect property bindings or QML file loading issues. The bindQmlPropertyToAttribute table must include leftBlinkerActive and rightBlinkerActive mappings to their respective state properties. QML file path verification requires confirming qmlFilename = "examples/dashboard-with-blinkers.qml" accuracy, and the QML object name must match qmlDataItemObjectName = "state" specification.
| Class | Base Class | Purpose | Location |
|---|---|---|---|
DtVehicleBlinkerControlLogic | DtEntityControlLogic | Frontend input handling and UI integration | vehicleBlinkerFrontend/ |
DtVehicleBlinkerActuator | DtActuatorComponent | Backend state modification and lighting control | vehicleBlinkerSim/ |
DtVehicleBlinkerDescriptor | DtActuatorComponentDescriptor | Actuator configuration and port mapping | vehicleBlinkerSim/ |
| File | Purpose | Key Content |
|---|---|---|
driver-with-blinkers.lua | Role configuration with blinker support | Component setup, state properties, QML bindings |
vehicleBlinkerInput.lua | Input device mapping | Keyboard bindings: ',' → left, '.' → right |
vehicle-blinkers.sysdef | VR-Forces system definition | Joystick controller, actuator, port connections |
dashboard-with-blinkers.qml | Visual dashboard overlay | Blinker indicators, property bindings |
Light Strike Vehicle MK II.entity | Entity definition | Vehicle configuration with blinker system |
Frontend APIs:
DtEntityControlLogic::initialize() - Component initializationDtInputLogic::loadInputConfig() - Load key/button mappingsDtInputLogic::addActionHandler() - Register action callbackJoystickMessage::create() - Create command messageJoystickMessage::setEntityId() - Set target entityJoystickMessage::setFunctionGroup() - Set command groupJoystickMessage::setFunction() - Set command function nameJoystickMessage::setValue() - Set command value (button state)DtVreMessageManager::queueMessage() - Send message to backendBackend APIs:
DtActuatorComponent::createPorts() - Create input portsDtActuatorComponent::addInputPort() - Register input portDtBooleanInputPort::activeConnection() - Check if port connectedDtBooleanInputPort::newData() - Check for new messageDtBooleanInputPort::dataReceived() - Acknowledge messageDtBooleanInputPort::value() - Get port valueDtLocalObject::nextFrameStateProperties() - Access entity propertiesDtStateProperties::findProperty<>() - Retrieve property by nameDtRwBoolean::value() - Read boolean propertyDtRwBoolean::setValue() - Write boolean propertyDtLocalObject::hasStateComponent<>() - Check for state componentDtLocalObject::getNextFrameStateComponent<>() - Get state componentDtGroundVehicleLightingStateComponent::setLeftIndicatorLightsOn() - Set left blinkerDtGroundVehicleLightingStateComponent::setRightIndicatorLightsOn() - Set right blinker| Field | Description | Example Value |
|---|---|---|
| Entity ID | Target entity identifier | Player's current entity |
| Function Group | Command group name | "Vehicle-Blinkers" |
| Function | Specific command | "LeftBlinker", "RightBlinker" |
| Value | Command parameter | 1.0 (pressed), 0.0 (released) |
Input ports connect joystick functions to actuator logic via system definition:
| Port Name | Joystick Function | Function Group | Purpose |
|---|---|---|---|
left-blinker | LeftBlinker | Vehicle-Blinkers | Toggles left turn signal |
right-blinker | RightBlinker | Vehicle-Blinkers | Toggles right turn signal |
Connections configured in vehicle-blinkers.sysdef:
Entity state properties providing persistent blinker state:
| Property Name | Type | Default | QML Binding | Purpose |
|---|---|---|---|---|
left-blinker-active | bool | false | leftBlinkerActive | Left turn signal status |
right-blinker-active | bool | false | rightBlinkerActive | Right turn signal status |
Properties defined in role configuration and bound to QML dashboard for real-time visual feedback.
vehicleBlinkerFrontend → exampleVehicleBlinkerFrontend.dllvehicleBlinkerSim → exampleVehicleBlinkerSim.dllplugins64/vrEngage/release/plugins64/vrForces/release/Related Documentation: