Log inGet started

Physics

The Physics namespace — the engine's Luau API reference for Physics.

The Physics namespace — 58 functions.

globals/Physics/addCollider

Physics.addCollider(entityId: string | entityProxy, component: string, config: table?)

Add a collider component to an entity, naming the shape you want.

Parameters

  • entityId string | entityProxy — Target entity id.
  • component string — One of Physics.COLLIDER_COMPONENTS.
  • config table (optional) — The component's own fields, e.g. { radius = 0.5 } for a sphere.
Physics.addCollider(id, "SphereCollider", { radius = 0.5 })

globals/Physics/addConstraint

Physics.addConstraint(entityId: string | entityProxy, opts: table?)

Add a transform constraint to an entity.

Parameters

  • entityId string | entityProxy — Target entity id.
  • opts table (optional) — Optional constraint description (targetEntityId, position, rotation, scale, lookAt, targetPosition, axes, weight).
Physics.addConstraint(id, { targetEntityId = parent, position = true })

globals/Physics/addJoint

Physics.addJoint(entityIdA: string | entityProxy, entityIdB: string | entityProxy, opts: table?)

Add a Joint component connecting two entities. Accepts either vec3-style anchor inputs (localAnchor = {x,y,z}) or pre-split scalar keys (localAnchorX/Y/Z).

Parameters

  • entityIdA string | entityProxy — Entity that hosts the Joint component.
  • entityIdB string | entityProxy — Connected entity.
  • opts table (optional) — Optional joint description (kind, anchors, axis, stiffness, damping, restLength, maxDistance, breakForce, breakTorque).
Physics.addJoint(a, b, { kind = "fixed" })
Physics.addJoint(a, b, { kind = "hinge", axis = {x=0,y=1,z=0} })
Physics.addJoint(a, b, { kind = "rope", maxDistance = 8 })
Physics.addJoint(a, b, { kind = "fixed", breakForce = 1200, breakTorque = 800 })

globals/Physics/addVelocity

Physics.addVelocity(a: string | entityProxy | number | vec3, b: (number | vec3)?, c: number?, d: number?)

Add to the linear velocity of an entity. Same call shapes as setVelocity.

Parameters

  • a string | entityProxy | number | vec3 — dx, a {x, y, z} delta vector, or an entity id (explicit target).
  • b (number | vec3) (optional) — dy, dx, or the delta vector depending on call form.
  • c number (optional) — dz or dy depending on call form.
  • d number (optional) — Optional dz when targeting an explicit entity.
Physics.addVelocity(0, 5, 0)
Physics.addVelocity(entityId, 0, 5, 0)
Physics.addVelocity(entityId, {x=0, y=5, z=0})

globals/Physics/addWheelCollider

Physics.addWheelCollider(entityId: string | entityProxy, config: table?)

Add a WheelCollider to an entity. The entity must be a child (or descendant) of a rigid body — the system walks up the hierarchy to find the Physics component.

Parameters

  • entityId string | entityProxy — Target entity id.
  • config table (optional) — Optional wheel configuration (radius?, suspensionDistance?, springRate?, damperRate?, motorTorque?, brakeTorque?, steerAngle?, forwardFriction?, sidewaysFriction?, is2D?).
Physics.addWheelCollider(id, { radius = 0.35, motorTorque = 500 })

globals/Physics/applyForce

Physics.applyForce(entityIdOrForce: string | entityProxy | vec3, force: vec3?)

Apply a force to an entity's rigid body for the next physics step — call every frame for continuous thrust. With one argument the script-context entity is targeted; with two args the explicit entity id wins.

Parameters

  • entityIdOrForce string | entityProxy | vec3 — Entity id (when paired with force) OR a force vector for the script-context entity.
  • force vec3 (optional) — Optional force vector when targeting an explicit entity.
Physics.applyForce({x=0, y=10, z=0})
Physics.applyForce(entityId, {x=0, y=10, z=0})

globals/Physics/applyForceAtPoint

Physics.applyForceAtPoint(entityId: string | entityProxy, force: vec3, point: vec3)

Apply a force at a specific world-space point — generates the matching torque from the lever arm.

Parameters

  • entityId string | entityProxy — Target entity id.
  • force vec3 — Force vector.
  • point vec3 — World-space application point.
Physics.applyForceAtPoint(id, {x=0,y=10,z=0}, {x=1,y=0,z=0})

globals/Physics/applyImpulse

Physics.applyImpulse(entityIdOrImpulse: string | entityProxy | vec3, impulse: vec3?)

Apply an instantaneous impulse (one-shot velocity change). With one argument the script-context entity is targeted; with two args the explicit entity id wins.

Parameters

  • entityIdOrImpulse string | entityProxy | vec3 — Entity id (with impulse) OR an impulse vector for the script-context entity.
  • impulse vec3 (optional) — Optional impulse vector when targeting an explicit entity.
Physics.applyImpulse({x=0, y=5, z=0})
Physics.applyImpulse(entityId, {x=0, y=5, z=0})

globals/Physics/applyTorque

Physics.applyTorque(entityIdOrTorque: string | entityProxy | vec3, torque: vec3?)

Apply a torque to an entity's rigid body for the next physics step — call every frame for continuous spin-up. With one argument the script-context entity is targeted; with two args the explicit entity id wins.

Parameters

  • entityIdOrTorque string | entityProxy | vec3 — Entity id (with torque) OR a torque vector for the script-context entity.
  • torque vec3 (optional) — Optional torque vector when targeting an explicit entity.
Physics.applyTorque({x=0, y=1, z=0})
Physics.applyTorque(entityId, {x=0, y=1, z=0})

globals/Physics/bodyState

Physics.bodyState(entityId: string | entityProxy) -> PhysicsBodyState?

Everything the solver holds for one body — its type, mass, centre of mass, inertia, gravity scale, damping, lock flags, CCD, collision groups, sleep state, velocities, the force and torque queued for the next step, its colliders, contacts, joints and transform constraints, and why it is not moving.

Parameters

  • entityId string | entityProxy — Entity id or proxy.

Returns PhysicsBodyState? — A PhysicsBodyState — with exists = false for an entity that carries no rigid body — or nil when nothing in the scene answers to that id.

local b = Physics.bodyState(id); print(b.bodyType, b.mass, b.stillness)
if not Physics.bodyState(id).exists then print("no body was built") end

globals/Physics/boxCast

Physics.boxCast(origin: vec3, halfExtents: vec3, direction: vec3, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast a box along a direction and return the first hit.

Parameters

  • origin vec3 — Box center at the start of the cast.
  • halfExtents vec3 — Half the size of the box on each axis.
  • direction vec3 — Cast direction.
  • maxDistance number (optional) — Optional distance limit.
  • exclude (string | {string}) (optional) — Optional entity id, or array of entity ids, to exclude from hits. Applied while sweeping rather than to the answer, so a cast that starts inside an excluded collider reports what is behind it.

Returns table? — Hit table { entityId, point, normal, distance, startedInside }, or nil if nothing hit. startedInside is false for a surface the query crossed on its way there, and true when the query's own start already lay inside that collider — where distance is 0, point is the start itself, and normal is the shortest way out of the collider. normal is a unit vector either way.

local hit = Physics.boxCast(o, {x=0.5,y=0.5,z=0.5}, dir, 10)
local hit = Physics.boxCast(o, {x=0.5,y=0.5,z=0.5}, dir, 10, { selfId, carriedId })

globals/Physics/capsuleCast

Physics.capsuleCast(origin: vec3, radius: number, halfHeight: number, direction: vec3, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast an upright capsule along a direction and return the first hit. This is the sweep that answers whether a body of that shape fits through a passage: a capsule of radius r reports a hit on anything that leaves it less than 2 * r of clearance.

Parameters

  • origin vec3 — Capsule centre at the start of the cast.
  • radius number — Capsule radius.
  • halfHeight number — Distance from the centre to either cap centre. The capsule stands halfHeight + radius tall in each direction.
  • direction vec3 — Cast direction.
  • maxDistance number (optional) — Optional distance limit.
  • exclude (string | {string}) (optional) — Optional entity id, or array of entity ids, to exclude from hits. Applied while sweeping rather than to the answer, so a cast that starts inside an excluded collider reports what is behind it.

Returns table? — Hit table { entityId, point, normal, distance, startedInside }, or nil if nothing hit. startedInside is false for a surface the query crossed on its way there, and true when the query's own start already lay inside that collider — where distance is 0, point is the start itself, and normal is the shortest way out of the collider. normal is a unit vector either way.

local hit = Physics.capsuleCast(o, 0.3, 0.6, dir, 0.5)
local hit = Physics.capsuleCast(o, 0.3, 0.6, dir, 0.5, selfId)

globals/Physics/colliderGeometry

Physics.colliderGeometry(options: table?) -> table?

Read the physics world as drawable triangles: every collider triangulated in world space into one indexed mesh, in GPU buffers ready to draw.

Box, sphere, capsule, cylinder, cone, convex, triangle-mesh and heightfield colliders return their real surface, and a compound returns its children folded together; a shape with no triangulation returns its bounding box and reports exact = false.

options.colors is POSITIONAL over colliderManifest() — entry i colours collider i — so you can colour by role, shape, entity or anything else you read there. A position you leave out takes options.defaultColor.

The returned buffers are yours: destroy them when you replace them.

Parameters

  • options table (optional){ tessellation = "low"|"medium"|"high", colors = { {r,g,b,a}, ... }, defaultColor = {r,g,b,a} }.

Returns table?{ vertices, indices, vertexCount, indexCount, colliders } where each entry of colliders is { entity, colliderName?, shapeType, role, exact, firstIndex, indexCount }.

local geo = Physics.colliderGeometry({ tessellation = "high" })

globals/Physics/colliderManifest

Physics.colliderManifest() -> table

List every physics collider in the world with what it is and what it takes part in — no geometry, so it is the cheap read to make before deciding what to do with each one.

role is one of static, dynamic, kinematic, sensor. A sensor is a collider the simulation holds as one, reported ahead of the body type behind it, and a collider with no rigid body is static. exact says whether colliderGeometry would return this collider's true surface or its bounding box.

Every collider of one entity shares its entity, so this is what to key per-object decisions on. The order is stable across calls over an unchanged world, which is what makes colliderGeometry's positional colours usable.

Returns table — Array of { entity, colliderName?, shapeType, role, exact }.

for _, c in ipairs(Physics.colliderManifest()) do print(c.entity, c.role) end

globals/Physics/colliderOn

Physics.colliderOn(entityId: string | entityProxy) -> string?

Which collider component an entity carries, or nil when it carries none.

Parameters

  • entityId string | entityProxy — Target entity id.

Returns string? The component name, e.g. "SphereCollider".

local which = Physics.colliderOn(id)

globals/Physics/colliderShapes

Physics.colliderShapes(entityId: string | entityProxy) -> table

Read an entity's resolved physics collider shape(s) as the physics engine sees them, including auto-sized colliders.

shapeType is one of box, sphere, capsule, convex, mesh, heightfield, compound, other — the shape the simulation is running, so a mesh collider reads mesh.

params carries half-extents for a box, radius for a sphere, radius and half-height for a capsule, and the collider's bounding half-extents for the shapes that have no parametric description. A convex collider reports its outline in linePoints instead.

Parameters

  • entityId string | entityProxy — Target entity id.

Returns table — Array of resolved collider shapes (empty if none): { shapeType, position, rotation, params, linePoints, name? }.

local shapes = Physics.colliderShapes(id)

globals/Physics/contacts

Physics.contacts(entityId: string | entityProxy) -> { PhysicsContact }

Every contact one body's colliders are in right now, with the other entity, the normal, how deeply the two interpenetrate, the impulse the last step applied, and each contact point.

Parameters

  • entityId string | entityProxy — Entity id or proxy.

Returns { PhysicsContact } — An array of PhysicsContact — empty when the body touches nothing, or when the entity carries no rigid body.

for _, c in Physics.contacts(id) do print(c.other, c.deepestPenetration) end

globals/Physics/getAngularVelocity

Physics.getAngularVelocity(entityId: (string | entityProxy)?) -> vec3?

Read the angular velocity of an entity's rigid body.

Parameters

  • entityId (string | entityProxy) (optional) — Target entity id or proxy; resolves from script context when omitted.

Returns vec3? — Angular velocity in rad/s, or nil if the entity has no rigid body.

local w = Physics.getAngularVelocity(id)

globals/Physics/getGravity

Physics.getGravity() -> vec3

Read the current world gravity vector.

Returns vec3 — Gravity vector in m/s² (negative y is "down" in the default world).

local g = Physics.getGravity()

globals/Physics/getVelocity

Physics.getVelocity(entityId: (string | entityProxy)?) -> vec3?

Read the linear velocity of an entity's rigid body.

Parameters

  • entityId (string | entityProxy) (optional) — Target entity id or proxy; resolves from script context when omitted.

Returns vec3? — Velocity in m/s, or nil if the entity has no rigid body.

local v = Physics.getVelocity(id)

globals/Physics/getWheelState

Physics.getWheelState(entityId: string | entityProxy) -> table?

Read a wheel collider's runtime state. Reads the native component the wheel system writes after each physics step.

Parameters

  • entityId string | entityProxy — Target entity id (must carry a WheelCollider component).

Returns table?{ isGrounded, compression, angularVelocity }, or nil if the component is absent.

local state = Physics.getWheelState(id)

globals/Physics/hasLineOfSight

Physics.hasLineOfSight(fromId: string, toId: string) -> boolean

Check whether two entities have line-of-sight between their origins.

Parameters

  • fromId string — Viewer entity id.
  • toId string — Target entity id.

Returns booleantrue when no collider sits between them (including coincident origins), false otherwise.

if Physics.hasLineOfSight(a, b) then ... end

globals/Physics/ignoreCollision

Physics.ignoreCollision(entityIdA: string | entityProxy, entityIdB: string | entityProxy, ignore: boolean?)

Toggle ignored-collision state between two specific entities.

Parameters

  • entityIdA string | entityProxy — First entity id.
  • entityIdB string | entityProxy — Second entity id.
  • ignore boolean (optional) — When true (default) collisions between the pair are skipped.
Physics.ignoreCollision(a, b, true)

globals/Physics/isSleeping

Physics.isSleeping(entityId: (string | entityProxy)?) -> boolean?

Whether an entity's rigid body is currently asleep (at rest and not simulating). A body sleeps once it stops moving, to save simulation cost.

Parameters

  • entityId (string | entityProxy) (optional) — Target entity id or proxy; resolves from script context when omitted.

Returns boolean?true if asleep, false if awake, or nil if the entity has no rigid body.

if Physics.isSleeping(id) then Physics.wakeUp(id) end

globals/Physics/jointBreaks

Physics.jointBreaks() -> table

Every joint that has broken since the last call to this function. A joint breaks when the reaction it carries exceeds the breakForce (newtons of linear reaction) or breakTorque (the angular row of the same reaction) its joint was given; each joint reports once and its constraint is already released when the record arrives. The 256 most recent are kept: a structure that comes apart while nothing reads them drops the oldest beyond that, as the engine's own queue does beyond 1024.

Returns table — Array of { entityId, connectedEntityId, kind, impulse, angularImpulse, force, torque, position }, oldest first.

for _, e in ipairs(Physics.jointBreaks()) do print(e.entityId, e.force) end

globals/Physics/jointReaction

Physics.jointReaction(entityId: string | entityProxy) -> table?

The load an entity's joint is carrying right now, as the constraint solver resolved it on the last physics step. This is the same quantity a break threshold is measured against, so it is what to size breakForce and breakTorque from.

Parameters

  • entityId string | entityProxy — Entity carrying the Joint component.

Returns table?{ impulse, angularImpulse, force, torque, position }, or nil when the entity owns no joint.

local r = Physics.jointReaction(id); print(r and r.force)

globals/Physics/observe

Physics.observe(entityId: (string | entityProxy)?, opts: table?) -> PhysicsObservation?

Read the solver's own state — the world's accounting, and what it holds for each body plus why it is not moving one. Every value comes off the simulation rather than the Physics component, so a write the solver refused or clamped reads back as what it kept. Answers in edit mode as well as play mode.

Parameters

  • entityId (string | entityProxy) (optional) — Report on this one entity. Omit for every body in the world.
  • opts table (optional){ bodies: boolean?, contactPoints: boolean? }bodies = false builds the world accounting alone, and contactPoints = false keeps each contact pair's normal, depth, impulse and point count while leaving out the individual points. Both default to true.

Returns PhysicsObservation? — A PhysicsObservation, or nil when entityId names nothing in the scene. bodies is an array, not a table keyed by entity id — each entry names its own entity in entity.

local o = Physics.observe(); for _, b in o.bodies do print(b.entity, b.stillness) end
local o = Physics.observe(id); print(o.bodies[1].stillness, o.bodies[1].stillnessDetail)

globals/Physics/onJointBreak

Physics.onJointBreak(fn: (table) -> ()) -> () -> ()

Call fn for every joint that breaks from now on, with the same record jointBreaks returns.

Parameters

  • fn (table) -> () — Receives one break record per broken joint.

Returns () -> () — A function that removes this listener.

local off = Physics.onJointBreak(function(e) print(e.kind, e.force, e.position) end)

globals/Physics/overlapSphere

Physics.overlapSphere(center: vec3, radius: number) -> table

Find every entity id whose colliders overlap a sphere.

Parameters

  • center vec3 — Sphere center in world space.
  • radius number — Sphere radius.

Returns table — Array of overlapping entity ids.

local ids = Physics.overlapSphere({x=0,y=0,z=0}, 5)

globals/Physics/pumpJointBreaks

Physics.pumpJointBreaks()

Deliver every joint break the simulation has recorded to the registered listeners. An enabled Joint component calls this each tick, so listeners fire on their own wherever joints come from that component. A joint made by writing ecs.PhysicsJoint directly has no such tick behind it — call this each frame, or poll jointBreaks, to deliver its breaks.

Physics.pumpJointBreaks()

globals/Physics/raycast

Physics.raycast(origin: vec3, direction: vec3, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast a ray and return the first hit.

Parameters

  • origin vec3 — Ray origin in world space.
  • direction vec3 — Ray direction (does not need to be unit-length; the engine normalises).
  • maxDistance number (optional) — Maximum distance along the ray (defaults to 1000).
  • exclude (string | {string}) (optional) — Optional entity id, or array of entity ids, to exclude from hits.

Returns table? — Hit table { entityId, point, normal, distance, startedInside }, or nil if nothing hit. startedInside is false for a surface the query crossed on its way there, and true when the query's own start already lay inside that collider — where distance is 0, point is the start itself, and normal is the shortest way out of the collider. normal is a unit vector either way.

local hit = Physics.raycast({x=0,y=2,z=0}, {x=0,y=-1,z=0})
local hit = Physics.raycast(origin, dir, 50, { selfId, carriedId })

globals/Physics/raycastAll

Physics.raycastAll(origin: vec3, direction: vec3, maxDistance: number?, maxHits: number?, exclude: (string | {string})?) -> table

Cast a ray and return every hit up to maxHits.

Parameters

  • origin vec3 — Ray origin in world space.
  • direction vec3 — Ray direction.
  • maxDistance number (optional) — Optional distance limit along the ray.
  • maxHits number (optional) — Optional cap on the number of hits returned.
  • exclude (string | {string}) (optional) — Optional entity id, or array of entity ids, to exclude from hits.

Returns table — Array of hit tables { entityId, point, normal, distance, startedInside } — empty when nothing was hit. startedInside is false for a surface the query crossed on its way there, and true when the query's own start already lay inside that collider — where distance is 0, point is the start itself, and normal is the shortest way out of the collider. normal is a unit vector either way.

local hits = Physics.raycastAll(origin, dir, 50, 4)

globals/Physics/raycastBetween

Physics.raycastBetween(fromId: string, toId: string, maxDistance: number?) -> table?

Cast a ray from one entity toward another and return the first hit.

Parameters

  • fromId string — Origin entity id.
  • toId string — Target entity id.
  • maxDistance number (optional) — Optional distance cap (default 1000).

Returns table? — Hit table, or nil if the entities are coincident or nothing was hit.

local hit = Physics.raycastBetween(a, b)

globals/Physics/raycastScreen

Physics.raycastScreen(sx: number, sy: number, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast a ray from a screen pixel into the scene and return the first hit. Unprojects the pixel with screenToRay, then casts with raycast.

Parameters

  • sx number — Screen X in viewport-local pixels (the space of input.mouse_position and screenToRay).
  • sy number — Screen Y in viewport-local pixels.
  • maxDistance number (optional) — Maximum distance along the ray (defaults to 1000, matching raycast).
  • exclude (string | {string}) (optional) — Optional entity id, or array of entity ids, to exclude from hits.

Returns table? — Hit table { entityId, point, normal, distance, startedInside }, or nil on a miss or when no camera has rendered yet. startedInside is false for a surface the query crossed on its way there, and true when the query's own start already lay inside that collider — where distance is 0, point is the start itself, and normal is the shortest way out of the collider. normal is a unit vector either way.

local m = input.mouse_position; local hit = Physics.raycastScreen(m[1], m[2])

globals/Physics/removeCollider

Physics.removeCollider(entityId: string | entityProxy) -> string?

Remove whichever collider component an entity carries.

Parameters

  • entityId string | entityProxy — Target entity id.

Returns string? The component that was removed, or nil when there was none.

Physics.removeCollider(id)

globals/Physics/removeConstraint

Physics.removeConstraint(entityId: string | entityProxy, index: number?)

Remove transform constraints from an entity (if any are present).

Parameters

  • entityId string | entityProxy — Target entity id.
  • index number (optional) — Optional constraint index (currently ignored — the whole component is removed).
Physics.removeConstraint(id)

globals/Physics/removeJoint

Physics.removeJoint(entityId: string | entityProxy)

Remove the Joint component from an entity (if present).

Parameters

  • entityId string | entityProxy — Target entity id.
Physics.removeJoint(id)

globals/Physics/removeWheelCollider

Physics.removeWheelCollider(entityId: string | entityProxy)

Remove the WheelCollider component from an entity (if present).

Parameters

  • entityId string | entityProxy — Target entity id.
Physics.removeWheelCollider(id)

globals/Physics/setAngularDamping

Physics.setAngularDamping(entityIdOrDamping: string | entityProxy | number, damping: number?)

Set angular damping on an entity's rigid body. One-arg form targets the script-context entity.

Parameters

  • entityIdOrDamping string | entityProxy | number — Entity id (with damping) OR damping value (script-context entity).
  • damping number (optional) — Optional explicit damping when targeting another entity.
Physics.setAngularDamping(0.1)
Physics.setAngularDamping(entityId, 0.1)

globals/Physics/setAngularVelocity

Physics.setAngularVelocity(a: string | entityProxy | number | vec3, b: (number | vec3)?, c: number?, d: number?)

Set the angular velocity of an entity (radians/sec). Same call shapes as setVelocity.

Parameters

  • a string | entityProxy | number | vec3 — x-component, a {x, y, z} vector, or an entity id (explicit target).
  • b (number | vec3) (optional) — y-component, x-component, or the vector depending on call form.
  • c number (optional) — z-component or y-component depending on call form.
  • d number (optional) — Optional z-component when targeting an explicit entity.
Physics.setAngularVelocity(0, 0, 1)
Physics.setAngularVelocity(entityId, 0, 0, 1)
Physics.setAngularVelocity(entityId, {x=0, y=0, z=1})

globals/Physics/setBodyType

Physics.setBodyType(entityId: string | entityProxy, bodyType: string)

Change a rigid body's type at runtime. Mass, colliders, and joints are preserved — only the body's response to forces and position writes changes.

Parameters

  • entityId string | entityProxy — Target entity id.
  • bodyType string — One of "dynamic", "kinematic", "static".
Physics.setBodyType(entityId, "kinematic")

globals/Physics/setCcdEnabled

Physics.setCcdEnabled(entityIdOrEnabled: string | entityProxy | boolean, enabled: boolean?)

Enable or disable continuous collision detection on an entity's rigid body. One-arg form targets the script-context entity.

Parameters

  • entityIdOrEnabled string | entityProxy | boolean — Entity id (with enabled) OR boolean (script-context entity).
  • enabled boolean (optional) — Optional explicit boolean when targeting another entity.
Physics.setCcdEnabled(true)
Physics.setCcdEnabled(entityId, true)

globals/Physics/setCollisionGroups

Physics.setCollisionGroups(entityId: string | entityProxy, membership: number, filter: number)

Set the collision-group membership and filter bitmasks on an entity's colliders. Adds a CollisionGroup component if missing.

Parameters

  • entityId string | entityProxy — Target entity id.
  • membership number — Bitmask: which groups this collider belongs to.
  • filter number — Bitmask: which groups this collider can collide with.
Physics.setCollisionGroups(id, 0x0001, 0xFFFF)

globals/Physics/setGravity

Physics.setGravity(gravity: vec3)

Replace the world gravity vector.

Parameters

  • gravity vec3 — New gravity vector in m/s².
Physics.setGravity({x=0, y=-9.81, z=0})

globals/Physics/setGravityScale

Physics.setGravityScale(entityIdOrScale: string | entityProxy | number, scale: number?)

Set the per-entity gravity scale (1.0 = normal, 0.0 = no gravity). One-arg form targets the script-context entity.

Parameters

  • entityIdOrScale string | entityProxy | number — Entity id (with scale) OR scale value (script-context entity).
  • scale number (optional) — Optional explicit scale when targeting another entity.
Physics.setGravityScale(0.5)
Physics.setGravityScale(entityId, 0.5)

globals/Physics/setJointMotor

Physics.setJointMotor(entityId: string | entityProxy, targetVelocity: number, maxForce: number)

Set a motor on an entity's joint.

Parameters

  • entityId string | entityProxy — Target entity id (must carry a Joint component).
  • targetVelocity number — Desired joint velocity.
  • maxForce number — Maximum force the motor can apply.
Physics.setJointMotor(id, 5.0, 1000)

globals/Physics/setLinearDamping

Physics.setLinearDamping(entityIdOrDamping: string | entityProxy | number, damping: number?)

Set linear damping on an entity's rigid body (0 = no damping). One-arg form targets the script-context entity.

Parameters

  • entityIdOrDamping string | entityProxy | number — Entity id (with damping) OR damping value (script-context entity).
  • damping number (optional) — Optional explicit damping when targeting another entity.
Physics.setLinearDamping(0.05)
Physics.setLinearDamping(entityId, 0.05)

globals/Physics/setMass

Physics.setMass(entityIdOrMass: string | entityProxy | number, mass: number?)

Set the mass of an entity's rigid body (kg). One-arg form targets the script-context entity.

Parameters

  • entityIdOrMass string | entityProxy | number — Entity id (with mass) OR mass value (script-context entity).
  • mass number (optional) — Optional explicit mass when targeting another entity.
Physics.setMass(10)
Physics.setMass(entityId, 10)

globals/Physics/setRotationLocks

Physics.setRotationLocks(entityId: string | entityProxy, x: boolean, y: boolean, z: boolean)

Lock or unlock rotation on specific axes.

Parameters

  • entityId string | entityProxy — Target entity id.
  • x boolean — Lock rotation about the world X axis.
  • y boolean — Lock rotation about the world Y axis.
  • z boolean — Lock rotation about the world Z axis.
Physics.setRotationLocks(id, false, true, false)

globals/Physics/setTranslationLocks

Physics.setTranslationLocks(entityId: string | entityProxy, x: boolean, y: boolean, z: boolean)

Lock or unlock translation on specific axes.

Parameters

  • entityId string | entityProxy — Target entity id.
  • x boolean — Lock translation along the world X axis.
  • y boolean — Lock translation along the world Y axis.
  • z boolean — Lock translation along the world Z axis.
Physics.setTranslationLocks(id, false, false, true)

globals/Physics/setVelocity

Physics.setVelocity(a: string | entityProxy | number | vec3, b: (number | vec3)?, c: number?, d: number?)

Set the linear velocity of an entity. Accepts (x, y, z) or a {x, y, z} vector for the script-context entity, or the same prefixed with an explicit entityId.

Parameters

  • a string | entityProxy | number | vec3 — x-component, a {x, y, z} vector, or an entity id (explicit target).
  • b (number | vec3) (optional) — y-component, x-component, or the vector depending on call form.
  • c number (optional) — z-component or y-component depending on call form.
  • d number (optional) — Optional z-component when targeting an explicit entity.
Physics.setVelocity(0, 10, 0)
Physics.setVelocity(entityId, 0, 10, 0)
Physics.setVelocity(entityId, {x=0, y=10, z=0})

globals/Physics/sphereCast

Physics.sphereCast(origin: vec3, radius: number, direction: vec3, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast a sphere along a direction and return the first hit.

Parameters

  • origin vec3 — Sphere center at the start of the cast.
  • radius number — Sphere radius.
  • direction vec3 — Cast direction.
  • maxDistance number (optional) — Optional distance limit.
  • exclude (string | {string}) (optional) — Optional entity id, or array of entity ids, to exclude from hits. Applied while sweeping rather than to the answer, so a cast that starts inside an excluded collider reports what is behind it.

Returns table? — Hit table { entityId, point, normal, distance, startedInside }, or nil if nothing hit. startedInside is false for a surface the query crossed on its way there, and true when the query's own start already lay inside that collider — where distance is 0, point is the start itself, and normal is the shortest way out of the collider. normal is a unit vector either way.

local hit = Physics.sphereCast(o, 0.5, dir, 10)
local hit = Physics.sphereCast(o, 0.5, dir, 10, selfId)

globals/Physics/stepCost

Physics.stepCost() -> PhysicsStepCost?

What the last physics step cost, stage by stage — the same figures worldState().step carries, for a caller that wants only these. Each covers that one step rather than a window of them, and consecutive steps over the same resting scene vary by tens of percent, so several samples averaged is the honest read of what a step costs.

Returns PhysicsStepCost? — A PhysicsStepCost, or nil on a frame where the pipeline did not step — a paused simulation, or a world still bootstrapping.

local c = Physics.stepCost(); if c then print(c.stepMs, c.narrowPhaseMs) end

globals/Physics/stillnessReasons

Physics.stillnessReasons() -> { string }

Every reason whyStill can answer with, in the order the engine considers them. Read from the engine, so the list is the one the answers come from.

Returns { string } — An array of reason names.

for _, reason in Physics.stillnessReasons() do print(reason) end

globals/Physics/touching

Physics.touching(entityId: string | entityProxy, otherId: string | entityProxy) -> (boolean, number, { PhysicsContactPoint })

Whether two entities are touching, and how deeply.

Parameters

  • entityId string | entityProxy — Entity id or proxy.
  • otherId string | entityProxy — The other entity id or proxy.

Returns (boolean, number, { PhysicsContactPoint })(touching, deepestPenetration, points)deepestPenetration is in metres and 0 for surfaces that meet without overlapping.

local hit, depth = Physics.touching(a, b); print(hit, depth)

globals/Physics/wakeUp

Physics.wakeUp(entityId: (string | entityProxy)?)

Wake an entity's sleeping rigid body so it resumes simulating. The motion setters (applyImpulse, setVelocity, setAngularVelocity) wake the body for you; call this to wake one explicitly.

Parameters

  • entityId (string | entityProxy) (optional) — Target entity id or proxy; resolves from script context when omitted.
Physics.wakeUp(id)

globals/Physics/whyStill

Physics.whyStill(entityId: string | entityProxy) -> (string?, string?)

Why the solver is not moving a body. Returns nil when it IS moving it, and otherwise one of noBody, simulationNotStepping, disabled, static, kinematic, infiniteMass, translationLocked, gravityDisabled, asleep, outsideIsland, resting, aboutToMove — the nearest cause, so the answer names the thing to change. A second return carries the detail: which collider it rests on and how deeply, what its effective gravity works out to, and so on.

Parameters

  • entityId string | entityProxy — Entity id or proxy.

Returns (string?, string?)(reason, detail).

local why, detail = Physics.whyStill(id); if why then print(why, detail) end

globals/Physics/worldState

Physics.worldState() -> PhysicsWorldState

How many bodies, colliders, joints and contacts the simulation holds right now, with world gravity, the timestep, whether the pipeline is stepping at all, and what the last step cost. Counted off the solver, so a body that failed to build is absent here while its Physics component still exists.

Returns PhysicsWorldState — A PhysicsWorldState.

local w = Physics.worldState(); print(w.bodies.awake .. "/" .. w.bodies.total .. " awake")
print(Physics.worldState().contacts.touchingPairs .. " pairs touching")
  • api
  • reference