Venus Lua API › Physics
Physics
Deterministic scene queries — raycasts, shape casts, overlaps.
lua/venus_lua/src/lua_physics.rs
Physics
A module singleton (global functions only, no handles) for querying the deterministic physics
world: raycasts, shape sweeps, overlap tests, and the layer-collision matrix. Fixed-point
results are converted to f32 at this script boundary.
All queries run against rigid bodies in the deterministic FixedXpbdWorld. Two consequences
that catch scripters:
- Triggers (sensors) are excluded from every query. A Collider with
SetTrigger(true)registers as a sensor and is invisible to raycasts, casts, overlaps, and
checks alike — the reverse of a solid collider. (KinematicControllers
are invisible too; they register no body at all.) - Only the distance-based casts merge voxel terrain. Raycast / Linecast and the shape casts
(SphereCast/CapsuleCast/BoxCast) fold terrain hits in by distance where a collision
world is wired. The overlap / check family (SphereTestAll,OverlapBox,CheckSphere,
CheckBox) tests rigid bodies only and never reports voxel terrain.
Vector arguments (origin, direction, center, halfExtents, …) take a Vector3.
layerMask is an integer bitmask selecting which layers the query tests.
Result tables
A single hit is a table { point: Vector3, normal: Vector3, distance: number, gameObject:
GameObject }. Multi-hit queries return a 1-based array of these (or of GameObjects, as noted).
A terrain hit’s
gameObjectis a dead handle, notnil. A voxel-terrain hit (from one of the
casts above) has no owning object, buthit.gameObjectis still a present GameObject userdata
wrapping the null handle — it is truthy, soif hit.gameObject thenis always true. Tell terrain
from a real body withGameObject.Exists(hit.gameObject)(false= terrain).
Functions
Physics.Raycast( Vector3 origin, Vector3 direction, integer layerMask ) : table or nil
Physics.Raycast( Vector3 origin, Vector3 direction, integer layerMask, number maxDistance ) : table or nil
Casts a ray and returns the closest hit as a {point, normal, distance, gameObject} table, or
nil if nothing was hit. maxDistance defaults to 10000 world units when omitted (not
unbounded); RaycastAll shares the same default.
Physics.RaycastAll( Vector3 origin, Vector3 direction, integer layerMask ) : table
Physics.RaycastAll( Vector3 origin, Vector3 direction, integer layerMask, number maxDistance ) : table
Returns an array of every hit along the ray (empty table if none).
Physics.LinecastAll( Vector3 start, Vector3 end, integer layerMask ) : table
Returns an array of all hits on the segment from start to end.
Physics.SphereTestAll( Vector3 center, number radius, integer layerMask ) : table
Returns an array of the GameObjects whose colliders overlap the sphere.
Physics.SphereCast( Vector3 center, number radius, Vector3 direction, number maxDistance, integer layerMask ) : table or nil
Sweeps a sphere and returns the closest hit, or nil.
Physics.CapsuleCast( Vector3 center, Quaternion rotation, number radius, number halfHeight, Vector3 direction, number maxDistance, integer layerMask ) : table or nil
Sweeps an oriented capsule and returns the closest hit, or nil.
Physics.BoxCast( Vector3 center, Quaternion rotation, Vector3 halfExtents, Vector3 direction, number maxDistance, integer layerMask ) : table or nil
Sweeps an oriented box and returns the closest hit, or nil.
Physics.OverlapBox( Vector3 center, Quaternion rotation, Vector3 halfExtents, integer layerMask ) : table
Returns an array of the GameObjects overlapping the oriented box.
Physics.CheckSphere( Vector3 center, number radius, integer layerMask ) : boolean
true if any collider overlaps the sphere.
Physics.CheckBox( Vector3 center, Quaternion rotation, Vector3 halfExtents, integer layerMask ) : boolean
true if any collider overlaps the oriented box.
Physics.IgnoreLayerCollision( integer a, integer b, boolean ignore ) : void
Sets whether layers a and b ignore each other in the solver (Unity semantics: ignore ==
true clears the collide bit). Intended for startup/config — the layer table is treated as
immutable during simulation. Out-of-range indices (≥ 32) are a no-op.
Physics.GetIgnoreLayerCollision( integer a, integer b ) : boolean
true if layers a and b are set not to collide. On a wired world, out-of-range
indices (≥ 32) return true (they cannot collide); only an unwired world returns false.
Constants
Physics exposes no constants. Force modes are quoted strings, not a constants table — see
FixedRigidBody → AddForce.
rb:AddForce(Vector3.new(0, 12, 0), "Impulse") -- correct
Removed (2026-07). A global
ForceModetable of integers (Force=0 …Acceleration=3)
used to be registered here. It was added for an earlier integer-taking rigid-body binding that
the fixed-dynamics rewrite retired; the replacement takes mode names, so every use of the
table silently appliedForce(luaL_checkstringcoerces1→"1", which matched nothing).
The table is gone, and an unrecognized mode name now raises a Lua error instead of defaulting.
ForceModeisnil— reaching for it is a loud error at the call site, which is the point.
Example
-- Ground check: cast a short ray straight down from the player.
function Script.Update(self)
local x, y, z = self.object:WorldPosition()
local hit = Physics.Raycast(Vector3.new(x, y, z), Vector3.new(0, -1, 0), self.groundMask, 1.2)
self.grounded = hit ~= nil
if hit then
-- hit.point, hit.normal, hit.distance, hit.gameObject
self.groundNormal = hit.normal
end
end