Venus Lua API › Physics
Collider
Collision shape on a GameObject — sphere, box, or capsule.
lua/venus_lua/src/lua_collider.rs
Collider
A collision shape attached to a GameObject — a sphere, an oriented or axis-aligned box, or a
capsule — plus a layer bitmask and a trigger flag. Enabling a solid collider registers a
static (mass-0) body in the deterministic FixedXpbdWorld, so dynamic bodies (like
DynamicCharacter) collide with it and Physics queries can hit
it. A trigger collider is the exception: a sensor produces no solid contact (bodies pass
through — it only fires OnTrigger* events) and is excluded from every Physics.* query. See
Trigger below. Note also that a KinematicController does
not collide with colliders at all — it sees only voxel terrain.
Static calls use the type table (Collider.Add(...)); instance methods use colon syntax on a
handle (collider:SetBox(...)).
Types
Collider — an opaque handle (userdata) to a collider component on a GameObject. It may go
stale when its component or GameObject is destroyed; a stale handle is safe to hold and pass
around. Calling a method whose receiver is not a Collider raises a type error — the one exception
is Collider.Exists, which is safe on any value. On a genuine but stale handle nothing raises:
getters log a warning and return nil, shape/config setters silently no-op, and Exists returns
false. tostring(collider) is always the literal string Collider (it never includes the
object’s name).
Known issue: A Collider is effectively static. Its collision body is placed once, at
on_enable, from the GameObject’s world transform, and is not re-posed when the GameObject
moves at runtime (engine/scenegraph/src/collider.rs:60). Moving a collider’s GameObject leaves
its collision surface behind at the enable-time pose. Re-posing happens only as a side effect of
calling a shape or filter setter — each rebuilds the body at the current transform via
sync_collider_shape. Author colliders where they belong, or re-call a setter after moving one.
Creation & Destruction
Collider.Add( GameObject gameObject ) : Collider
Attaches a new collider to gameObject and returns its handle. It starts as a degenerate
zero-extent AABB with layer mask 0xFFFFFFFF (all layers) and is not a trigger — call a shape
setter to give it geometry. Returns nil and logs an error if the component can’t be added (the
GameObject is invalid, it already has a collider, or the pool is exhausted). Raises a type error if
gameObject is not a GameObject.
Collider.Get( GameObject gameObject ) : Collider
Returns the collider on gameObject, or nil if it has none (no warning).
Collider.Exists( Collider collider ) : boolean
Returns true if the handle refers to a live collider. Safe on any value — a non-collider or
a stale handle returns false and never raises. (The one method that does not type-check its
receiver.)
There is no Destroy binding — a collider is removed with its GameObject; disabling the GameObject
unregisters its collision body, and re-enabling re-registers it.
Functions
Read-only queries.
collider:Active( ) : boolean or nil
The component’s own enabled flag — what Activate()/Deactivate() write. Logs a warning
(NotFound) and returns nil on a stale handle. This is intent, not effect: a collider whose
own flag is enabled but whose GameObject is deactivated still reports true.
collider:ActiveInHierarchy( ) : boolean or nil
true only when the own flag is enabled and the owning GameObject is active in hierarchy —
i.e. the component is actually running. This is the predicate the engine uses to gate update
dispatch. Returns nil on a stale handle.
Properties (get / set)
Setters rebuild the static fixed body so the change reaches the world. Both setters silently no-op
on a stale handle.
LayerMask
collider:LayerMask( ) : integer — the collider’s 32-bit layer bitmask (default 0xFFFFFFFF).
Logs a warning and returns nil on a stale handle.
collider:SetLayerMask( integer mask ) : void — sets the bitmask and rebuilds the static body
so the new mask reaches queries.
Trigger
collider:IsTrigger( ) : boolean — true if the collider is a trigger (sensor) volume. nil
- warning on a stale handle.
collider:SetTrigger( boolean on ): void — marks the collider as a trigger (Unity
isTrigger); overlaps then surface through the deterministic trigger-event pass
(OnTriggerEnter/Stay/Exit) instead of producing solid contacts.
Methods
Shape setters — bake the collider’s local geometry, then rebuild the static body at the current
transform. Every Vector3 argument must be a native Vector3 value; three loose numbers raise
a type error (unlike the GameObject setters, which accept either). All silently no-op on a stale
handle.
collider:SetSphere( Vector3 center, number radius ) : void
Sphere of radius, centered at local-space center. Orientation-free.
collider:SetAABB( Vector3 center, Vector3 halfExtents ) : void
Axis-aligned box with half-extents halfExtents at center. The body’s orientation is pinned to
identity — it ignores the GameObject’s rotation.
collider:SetBox( Vector3 center, Vector3 halfExtents ) : void
Oriented box — same half-extents as SetAABB, but the body tracks the GameObject’s rotation.
collider:SetCapsule( Vector3 center, number radius, number halfHeight ) : void
Y-axis capsule of radius and halfHeight (center to cap-center) at center. Tracks rotation.
Mesh colliders removed (2026-07-17):
SetTriangleMeshandSetConvexMeshare no longer
exposed to Lua. They never produced triangle-mesh or convex-hull collision — both silently
registered an oriented bounding box sized to the vertices’ AABB (FixedShape::Box), ignoring the
triangles/hull entirely (andSetTriangleMesh’sindicesoutright). The names promised fidelity
the code did not deliver, so the bindings were commented out (lua/venus_lua/src/lua_collider.rs;
scene glue inengine/scenegraph/src/scene.rs) pending a real mesh narrowphase. For non-box
geometry, decompose it into primitive colliders (sphere / box / capsule) yourself.
Lifecycle
Both silently no-op on a stale handle.
collider:Activate( ) : void
Sets the component’s own enabled flag. Its enable callback runs only if the owning GameObject is
also active — and it is that enable callback which registers the collision body.
collider:Deactivate( ) : void
Clears the own enabled flag; the disable callback runs only if the component was actually active.
Example
-- A box trigger zone on layer 3: reports OnTriggerEnter/Stay/Exit instead of blocking.
-- Vector3 args must be native Vector3 values (loose numbers raise a type error).
function Script.OnCreate(self)
local col = Collider.Add(self.object)
col:SetBox(Vector3.new(0, 0, 0), Vector3.new(0.5, 0.5, 0.5)) -- a 1-unit cube
col:SetLayerMask(1 << 3) -- only layer 3
col:SetTrigger(true)
-- The static body is seeded here at the object's world pose and is NOT re-posed
-- if the object later moves — re-call a setter after moving it.
end