Camera Mode: Unicycle
First-person walking camera for the unicycle vehicle. Handles ground detection, collision, gravity, VR snap-turning, and communicates rotation data back to the vehicle controller.
First-person walking camera for the unicycle vehicle. Handles ground detection, collision, gravity, VR snap-turning, and communicates rotation data back to the vehicle controller.
Overview
The unicycle camera provides a first-person walking experience. It performs raycasting to walk on terrain, applies simple gravity for falls, handles wall collisions at hip height, and supports OpenXR VR snap-turning. The camera rotation is sent back to the vehicle's playerController to steer the unicycle.
Class Properties
| Property | Type | Default | Description |
|---|---|---|---|
hidden | bool | true | Not in standard camera cycle |
pos | vec3 | computed | Current eye position |
rotVec | vec3 | computed | Current Euler rotation (yaw, pitch, roll) |
manualzoom | manualzoom | - | FOV zoom component (currently disabled) |
Methods
| Method | Signature | Description |
|---|---|---|
init | C:init() | Set up manualzoom and settings |
onSettingsChanged | C:onSettingsChanged() | Reload VR snap turn settings |
onCameraChanged | C:onCameraChanged(focused) | Load/restore unicycle UI layout |
reset | C:reset() | Reset zoom |
setCustomData | C:setCustomData(data) | Set initial pos/rotation from {pos, front, up} |
getPosRot | C:getPosRot() | Return current position and rotation quaternion |
update | C:update(data) | Process input, walk, apply camera |
Walking Physics
-- Constants
local humanHeight = 1.6
local maxFallHeight = 10
local gravity = -2
local teleportingSpeed = 1000 / 3.6 -- 277 m/s threshold
-- Ground detection: raycast from hip down
local hip = oldGround + vec3(0, 0, getHipHeight())
local newGround = castRayLocation(hip, oldGround + vec3(0, 0, -maxFallHeight))
-- Gravity: fall toward ground or into abyss
if newGround.z < oldGround.z then
newGround.z = max(oldGround.z + gravity * dt, newGround.z)
end
-- Wall collision: raycast at hip height
local hipCollisionPoint = castRayLocation(prevKnee, newKnee)
if hipCollisionPoint then
-- Stay 0.3m away from wall
newKnee = hipCollisionPoint + diff:normalized() * 0.3
endVR Snap Turning
-- OpenXR snap turn: discrete rotation steps
if self.openXRsnapTurnUnicycle then
if mustTurn then
self.rotVec.x = self.rotVec.x + sign(rdx) * self.openXRsnapTurnUnicycleDegrees
end
-- Re-trigger every 0.4 seconds when held
end
-- VR "look down" triggers 180° turn
if rdyNotMouse < -0.15 then
self.rotVec.x = self.rotVec.x + 180
endVehicle Communication
-- Send camera rotation to unicycle vehicle controller
data.veh:queueLuaCommand(
"controller.getControllerSafe('playerController').setCameraControlData("
.. serialize({cameraRotation = rotHorizontal}) .. ")"
)Settings
| Setting Key | Description |
|---|---|
openXRsnapTurnUnicycle | Enable VR snap turning |
openXRsnapTurnUnicycleDegrees | Degrees per snap turn |
Key Notes
- Uses
data.dtSimfor physics timing - Pitch clamped to ±89.9° (with float precision safety margin)
- Teleport detection: if position delta exceeds 277 m/s, reset
prevCamPos - Eye position = ground +
humanHeight(1.6m), crouching = 70% - Hip height = 45% of human height, used for collision checks
- Sends horizontal-only rotation to vehicle (pitch stripped for movement)
See Also
- Camera Mode: Autopoint - Related reference
- Camera Mode: Autozoom - Related reference
- Camera Mode: Big Map - Related reference
- Core Systems Guide - Guide
Camera Mode: Transition
Global filter that smoothly interpolates between camera states during camera mode switches and vehicle changes. Prevents jarring cuts by blending position, rotation, and FOV over a configurable durati
Input Action Filter
Blocks or allows specific input actions by name or group. Used to restrict player actions during missions, scenarios, and specific game states (e.g. disabling vehicle switching during a race).