`spawn` - Vehicle Spawning & Safe Placement
Core vehicle spawning, safe teleportation, and collision-free placement system. Handles creating vehicles, finding non-intersecting positions, ground snapping, and trailer coupling.
Core vehicle spawning, safe teleportation, and collision-free placement system. Handles creating vehicles, finding non-intersecting positions, ground snapping, and trailer coupling.
Exports
| Function | Signature | Description |
|---|---|---|
spawnVehicle | (model, partConfig, pos, rot, options?) → veh | Create and spawn a new vehicle |
setVehicleObject | (veh, options) | Configure and spawn an existing vehicle object |
spawnCamera | () | Create/find the game camera |
spawnPlayer | () | Spawn the default player vehicle |
pickSpawnPoint | (spawnName?) → object | Find a valid spawn point object |
safeTeleport | (veh, pos, rot, ...) | Teleport vehicle to a collision-free position |
teleportToLastRoad | (veh?, options?) | Teleport vehicle to nearest valid road position |
teleportToLastRoadCallback | (data, options) | Internal callback for road teleport |
calculateRelativeVehiclePlacement | (transform, offset0, offset1, rotOffset?) → MatrixF | Calculate transform for coupling |
placeTrailer | (vehId, couplerOffsetVeh, trailerId, couplerOffsetTrailer, couplerTag, rotOffset?) | Place and couple a trailer |
clearCache | () | Clear per-frame position caches |
How It Works
Spawning a Vehicle
spawnVehicle creates a BeamNGVehicle object, registers it, configures paint/config, and places it safely:
local pos = vec3(100, 200, 50)
local rot = quat(0, 0, 0, 1)
local veh = spawn.spawnVehicle("pickup", "vehicles/pickup/sport.pc", pos, rot, {
vehicleName = "myPickup",
paint = createVehiclePaint({x=1, y=0, z=0, w=1}),
autoEnterVehicle = true,
safeSpawn = true, -- default: true, uses safe placement
visibilityPoint = camPos, -- optional: avoid spawning behind walls relative to this point
removeTraffic = true, -- default: true, teleport traffic away from spawn
})Note: Vehicles are spawned rotated 180° around Z-axis internally (the engine convention).
Safe Teleportation
safeTeleport moves a vehicle to a position, then uses the safe placement algorithm to avoid collisions:
local veh = getPlayerVehicle(0)
local pos = vec3(500, 300, 100)
local rot = quatFromDir(vec3(0, 1, 0), vec3(0, 0, 1))
-- Full signature:
spawn.safeTeleport(veh, pos, rot,
false, -- checkOnlyStatics: skip vehicle intersection checks
camPos, -- visibilityPoint: ensure visible from here
true, -- removeTraffic: teleport traffic away
true, -- centeredPosition: pos is center, not refnode
true -- resetVehicle: reset physics (default true)
)Safe Placement Algorithm
The placement system finds a collision-free, ground-snapped position using a spiral search:
- Build bounding box from vehicle's collidable nodes (oriented OBB)
- Snap to ground via raycasts (3-point ground detection with terrain-following rotation)
- Check intersections against other vehicles (OBB vs node-level) and static geometry (raycasts)
- Visibility check via raycasts from the intended viewpoint - avoids spawning inside walls
- Spiral search if position is blocked - tests positions in expanding grid pattern (up to 400 candidates)
-- The algorithm prioritizes:
-- 1. No vehicle/static intersections
-- 2. Visible from camera (both directions)
-- 3. Not floating in air
-- 4. Closest to intended positionTeleport to Last Road
Recovers the vehicle to the nearest valid road position using the navigation map:
-- Basic recovery
spawn.teleportToLastRoad()
-- With options
spawn.teleportToLastRoad(veh, {
resetVehicle = true, -- reset physics on teleport
destinationPos = vec3(...) -- face toward this destination
})The algorithm:
- Scans recovery history points for one on a valid road
- Projects onto the road segment, offset to the legal driving side
- Respects one-way roads and driving-side rules (
rightHandDrive) - Falls back to closest road, then current position if no road found
Picking a Spawn Point
pickSpawnPoint searches for a valid spawn location in priority order:
local sp = spawn.pickSpawnPoint("player")
local pos = sp:getPosition()
local rot = quat(sp:getRotation())Search order:
- User's saved default spawn point (via
setSpawnpoint.loadDefaultSpawnpoint()) - Random point from groups:
CameraSpawnPoints→PlayerSpawnPoints→PlayerDropPoints DefaultPlayerSpawnSphere(backward compatibility)- Creates a new
SpawnSphereas fallback
Trailer Placement
-- Place trailer at coupler position relative to tow vehicle
spawn.placeTrailer(vehId,
vec3(0, 3, 0.2), -- coupler offset on tow vehicle
trailerId,
vec3(0.3, -3.3, 0), -- coupler offset on trailer
"tag_t", -- coupler tag
rotOffset -- optional rotation offset
)If the coupler tag is configured for "autoCouple", it automatically activates coupling after placement.
Internals
- Bounding boxes: Two BB builders -
buildBoundingBoxusesinitialCollidableNodePosBB(for reset vehicles),buildClusterBoundingBoxuses live node clusters (for deformed vehicles) - Ground snapping: 3-point raycast system that detects terrain angle and tilts the vehicle to match, with fallback for underground positions
- Intersection testing: OBB-OBB broad phase → per-node narrow phase. Large vehicles use distance checks; small vehicles (
avgSideLength < 0.5) use relaxed distance checks - Traffic handling: When
removeTraffic=true, traffic vehicles in the spawn area are force-teleported away viagameplay_traffic.forceTeleport - Per-frame cache:
vehiclesPositionedThisFrametracks vehicles spawned in the current frame so their BB can be computed from initial positions rather than (not-yet-updated) physics positions - 180° rotation: All rotations are pre-multiplied by
quat(0,0,1,0)to match engine convention where vehicles face backward in local space - Spiral search: Grid-based spiral pattern with step size proportional to vehicle dimensions, expanding outward up to 400 iterations
Common Patterns
-- Spawn and immediately drive
local veh = spawn.spawnVehicle("etk800", "vehicles/etk800/touring.pc", pos, rot)
core_vehicleBridge.executeAction(veh, 'setIgnitionLevel', 3)
-- Safe teleport for mission checkpoint
local cp = scenetree.findObject("checkpoint_3")
spawn.safeTeleport(veh, cp:getPosition(), quat(cp:getRotation()))
-- Recovery keybind
spawn.teleportToLastRoad()Exported Variables
preventPlayerSpawning- Exported variable - initialized asnil
Additional Exports
| Key | Signature | Description |
|---|---|---|
M.calculateRelativeVehiclePlacement | (transform0, coupler0_offset, coupler1_offset, rotOffset) | (No description available) |
M.clearCache | () | (No description available) |
M.pickSpawnPoint | (spawnName) | (No description available) |
M.placeTrailer | (vehId, couplerOffsetVeh, trailerId, couplerOffsetTrailer, couplerTag, rotOffset) | (No description available) |
M.safeTeleport | (veh, pos, rot, checkOnlyStatics_, visibilityPoint_, removeTraffic_, centeredPosition, resetVehicle) | TODO have separate options for "checkIntersectionTraffic", "checkIntersectionVehicles", "checkIntersectionStatic" |
M.setVehicleObject | (veh, options) | (No description available) |
M.spawnCamera | () | (No description available) |
M.spawnPlayer | () | (No description available) |
M.spawnVehicle | (model, partConfig, pos, rot, options) | NOTE: Spawns in the vehicle rotated by 180 degrees around the z-axis |
M.teleportToLastRoad | (veh, options) | (No description available) |
M.teleportToLastRoadCallback | (data, options) | (No description available) |
`simTimeAuthority` - Simulation Time & Bullet Time Control
Central authority for simulation speed (bullet time / slow motion), pausing, and smooth time-scale transitions. All pause and speed changes should go through this module.
`suspensionFrequencyTester` - Suspension Natural Frequency Analysis
Debug extension that measures suspension natural frequencies on the player vehicle's front and rear axles. Displays an ImGui window with frequency spectrum analysis and category matching (Luxury, Spor