rapier
stable3D rigid-body physics simulation powered by rapier3d, exposing a PhysicsWorld with rigid bodies, colliders, joints, raycasting, and per-body force/impulse control.
use plugin rapier::{Physics3D.world, step, set_gravity, …} Functions (39)
- Physics3D.world Create a new 3D physics world
- step Advance the simulation by one timestep
- set_gravity Set world gravity vector
- gravity Get current gravity vector
- set_timestep Set simulation timestep in seconds
- timestep Get current timestep
- raycast Cast a ray and return first hit
- create_rigid_body Add a rigid body to the world
- create_collider Attach a collider to a body
- create_joint Connect two bodies with a joint
- remove_joint Remove a joint from the world
- body_count Count rigid bodies in the world
- collider_count Count colliders in the world
- body_position Get body translation vector
- body_set_position Teleport a body to a position
- body_rotation Get body rotation quaternion
- body_linear_velocity Get body linear velocity vector
- body_set_linear_velocity Set body linear velocity
- body_apply_force Apply a continuous force to a body
- body_apply_impulse Apply an instant impulse to a body
- body_angular_velocity Get body angular velocity vector
- body_set_angular_velocity Set body angular velocity
- body_apply_torque Apply a continuous torque to a body
- body_apply_torque_impulse Apply an instant torque impulse
- body_mass Get body mass
- body_is_sleeping Check if body is sleeping
- body_wake_up Wake a sleeping body
- body_set_enabled Enable or disable a body
- body_is_enabled Check if body is enabled
- body_remove Remove a body from the world
- collider_set_restitution Set collider bounciness
- collider_restitution Get collider restitution
- collider_set_friction Set collider friction
- collider_friction Get collider friction
- collider_set_sensor Mark collider as sensor (no forces)
- collider_is_sensor Check if collider is a sensor
- collider_set_density Set collider density
- collider_remove Remove a collider from the world
- close Destroy the physics world
Overview
rapier wraps the rapier3d engine to give you a stateful 3D physics simulation.
Everything lives inside a PhysicsWorld resource that you create with
Physics3D.world; the world owns the rigid bodies, colliders, and joints, and it
advances in discrete steps. Rigid bodies and colliders are referenced by integer
handles returned at creation time, and every body/collider operation is a method
on the world that takes the relevant handle as its first argument.
The typical loop is: build a world, add fixed and dynamic bodies, attach
collider shapes to them, then call step() once per frame to integrate motion
under gravity. Between steps you can read state (positions, velocities, mass,
sleep status), push the simulation around with forces, impulses, torques, and
velocity setters, query the scene with raycast, and tear things down with the
*_remove and close helpers. Use it for games, simulations, or any scene that
needs believable collisions, stacking, and constraints.
Common patterns
Drop a ball onto a floor and watch it fall over several steps:
use plugin rapier::{Physics3D}
let world = Physics3D.world()
let floor = world.create_rigid_body(#{"type": "fixed", "position": #{"x": 0.0, "y": 0.0, "z": 0.0}})
world.create_collider(floor, #{"shape": #{"type": "cuboid", "hx": 5.0, "hy": 0.1, "hz": 5.0}})
let ball = world.create_rigid_body(#{"type": "dynamic", "position": #{"x": 0.0, "y": 5.0, "z": 0.0}})
let ball_col = world.create_collider(ball, #{"shape": #{"type": "ball", "radius": 0.5}})
world.collider_set_restitution(ball_col, 0.7)
for i in 0..60 {
world.step()
}
let pos = world.body_position(ball)
print("ball rested at y = {pos["y"]}")
world.close()
Launch a body with an impulse, then drive it with continuous force and torque:
use plugin rapier::{Physics3D}
let world = Physics3D.world()
let body = world.create_rigid_body(#{"type": "dynamic", "position": #{"x": 0.0, "y": 1.0, "z": 0.0}})
world.create_collider(body, #{"shape": #{"type": "ball", "radius": 0.5}})
world.body_apply_impulse(body, 0.0, 5.0, 0.0)
world.body_apply_force(body, 2.0, 0.0, 0.0)
world.body_apply_torque(body, 0.0, 1.0, 0.0)
world.step()
let vel = world.body_linear_velocity(body)
print("moving x = {vel["x"]}, y = {vel["y"]}")
world.close()
Cast a ray downward to find the ground beneath a point:
use plugin rapier::{Physics3D}
let world = Physics3D.world()
let floor = world.create_rigid_body(#{"type": "fixed", "position": #{"x": 0.0, "y": 0.0, "z": 0.0}})
world.create_collider(floor, #{"shape": #{"type": "cuboid", "hx": 10.0, "hy": 0.1, "hz": 10.0}})
let hit = world.raycast(#{
"origin": #{"x": 0.0, "y": 10.0, "z": 0.0},
"direction": #{"x": 0.0, "y": -1.0, "z": 0.0},
"max_distance": 100.0
})
if hit != nil {
print("ground at distance {hit["distance"]}")
}
world.close()
Create a new 3D physics world
Creates a new physics world. config is an optional table with gravity: #{x, y, z} and dt: float. Defaults to Earth gravity (0, -9.81, 0) and a standard timestep.
use plugin rapier::{Physics3D}
let world = Physics3D.world()
let custom = Physics3D.world(#{"gravity": #{"x": 0.0, "y": -1.62, "z": 0.0}, "dt": 0.016})
Advance the simulation by one timestep
Advances the simulation by one timestep. Call this once per frame.
world.step()
Run several steps in a loop to integrate motion over time:
for i in 0..120 {
world.step()
}
Set world gravity vector
Sets the gravity acceleration vector for the world.
world.set_gravity(0.0, -9.81, 0.0) // Earth
world.set_gravity(0.0, -1.62, 0.0) // Moon
Get current gravity vector
Returns the current gravity as #{x, y, z}.
let g = world.gravity()
print("gravity y: {g["y"]}")
Set simulation timestep in seconds
Sets the simulation timestep in seconds. Smaller values give higher accuracy but require more step() calls per second.
world.set_timestep(0.016) // ~60 Hz
Get current timestep
Returns the current timestep in seconds.
print(world.timestep())
Cast a ray and return first hit
Casts a ray and returns the first hit as #{distance, point: #{x,y,z}}, or nil if nothing is hit. Config fields: origin: #{x,y,z}, direction: #{x,y,z}, max_distance: float, exclude_body: int.
let hit = world.raycast(#{
"origin": #{"x": 0.0, "y": 10.0, "z": 0.0},
"direction": #{"x": 0.0, "y": -1.0, "z": 0.0},
"max_distance": 100.0
})
if hit != nil {
print("hit at distance {hit["distance"]}")
}
Use exclude_body to ignore the body firing the ray (useful for self-casts):
let hit = world.raycast(#{
"origin": #{"x": 0.0, "y": 2.0, "z": 0.0},
"direction": #{"x": 0.0, "y": -1.0, "z": 0.0},
"max_distance": 50.0,
"exclude_body": player
})
Add a rigid body to the world
Adds a rigid body and returns an integer handle. Config fields: type ("dynamic", "fixed", "kinematic_position", "kinematic_velocity"), position: #{x,y,z}, locked_rotations: bool, linear_damping: float, ccd: bool.
let floor = world.create_rigid_body(#{"type": "fixed", "position": #{"x": 0.0, "y": 0.0, "z": 0.0}})
let ball = world.create_rigid_body(#{"type": "dynamic", "position": #{"x": 0.0, "y": 5.0, "z": 0.0}})
Enable continuous collision detection and lock rotations for a fast projectile:
let bullet = world.create_rigid_body(#{
"type": "dynamic",
"position": #{"x": 0.0, "y": 1.0, "z": 0.0},
"ccd": true,
"locked_rotations": true,
"linear_damping": 0.1
})
Attach a collider to a body
Attaches a collider to a body and returns a collider handle. Config has a shape table with type ("ball", "cuboid", "capsule"), plus shape-specific fields (radius, hx/hy/hz, half_height).
let ball_col = world.create_collider(ball, #{"shape": #{"type": "ball", "radius": 0.5}})
let box_col = world.create_collider(floor, #{"shape": #{"type": "cuboid", "hx": 5.0, "hy": 0.1, "hz": 5.0}})
Capsules take both a half_height and a radius (handy for characters):
let player_col = world.create_collider(player, #{"shape": #{"type": "capsule", "half_height": 0.9, "radius": 0.4}})
Connect two bodies with a joint
Connects two bodies with a joint. Config type is "fixed", "revolute", "spherical", or "prismatic". Returns a joint handle. Fixed and spherical joints accept anchor1/anchor2 (#{x,y,z}); revolute and prismatic accept an axis (#{x,y,z}).
let j = world.create_joint(body_a, body_b, #{
"type": "revolute",
"axis": #{"x": 0.0, "y": 1.0, "z": 0.0}
})
A fixed joint rigidly welds two bodies at their local anchors:
let weld = world.create_joint(arm, hand, #{
"type": "fixed",
"anchor1": #{"x": 0.0, "y": -0.5, "z": 0.0},
"anchor2": #{"x": 0.0, "y": 0.5, "z": 0.0}
})
Remove a joint from the world
Removes a joint from the simulation by its integer handle.
world.remove_joint(j)
Count rigid bodies in the world
Returns the total number of rigid bodies in the world.
print("bodies: {world.body_count()}")
Count colliders in the world
Returns the total number of colliders in the world.
print("colliders: {world.collider_count()}")
Get body translation vector
Returns the body translation as #{x, y, z}.
let pos = world.body_position(ball)
print("ball y: {pos["y"]}")
Teleport a body to a position
Teleports a body to a position, waking it if sleeping.
world.body_set_position(ball, 0.0, 5.0, 0.0)
Get body rotation quaternion
Returns the body orientation as a quaternion #{x, y, z, w}.
let rot = world.body_rotation(ball)
print("rot w: {rot["w"]}")
Get body linear velocity vector
Returns the linear velocity as #{x, y, z}.
let vel = world.body_linear_velocity(ball)
print("speed y: {vel["y"]}")
Set body linear velocity
Sets the body's linear velocity directly.
world.body_set_linear_velocity(ball, 0.0, 10.0, 0.0)
Apply a continuous force to a body
Applies a continuous force (in world space) to the body's center of mass. Accumulates until the next step().
world.body_apply_force(ball, 0.0, 100.0, 0.0)
Apply an instant impulse to a body
Applies an instant change in momentum to the body.
world.body_apply_impulse(ball, 0.0, 5.0, 0.0)
Get body angular velocity vector
Returns the body's angular velocity as #{x, y, z} (radians per second about each axis).
let spin = world.body_angular_velocity(ball)
print("yaw rate: {spin["y"]}")
Set body angular velocity
Sets the body's angular velocity directly, waking it if asleep.
world.body_set_angular_velocity(top, 0.0, 20.0, 0.0)
Apply a continuous torque to a body
Applies a continuous torque (rotational force) to the body. Accumulates until the next step().
world.body_apply_torque(ball, 0.0, 1.0, 0.0)
Apply an instant torque impulse
Applies an instant angular impulse, immediately changing the body's spin.
world.body_apply_torque_impulse(ball, 0.0, 5.0, 0.0)
Get body mass
Returns the body's total mass in kilograms (computed from collider density).
print("mass: {world.body_mass(ball)} kg")
Check if body is sleeping
Returns true if the body has come to rest and the engine has put it to sleep.
if world.body_is_sleeping(ball) {
print("ball is at rest")
}
Wake a sleeping body
Forces a sleeping body back to the active simulation.
world.body_wake_up(ball)
Enable or disable a body
Enables or disables a body. A disabled body is removed from the simulation until re-enabled. Defaults to true when no value is given.
world.body_set_enabled(ball, false) // freeze it
world.body_set_enabled(ball, true) // bring it back
Check if body is enabled
Returns true if the body is currently participating in the simulation.
if !world.body_is_enabled(ball) {
world.body_set_enabled(ball, true)
}
Remove a body from the world
Removes a rigid body and all its attached colliders from the world.
world.body_remove(ball)
Set collider bounciness
Sets the bounciness coefficient (0.0 = no bounce, 1.0 = perfectly elastic).
world.collider_set_restitution(ball_col, 0.8)
Get collider restitution
Returns the collider's current restitution (bounciness) coefficient.
print("bounce: {world.collider_restitution(ball_col)}")
Set collider friction
Sets the friction coefficient for the collider surface.
world.collider_set_friction(ball_col, 0.5)
Get collider friction
Returns the collider's current friction coefficient.
print("friction: {world.collider_friction(ball_col)}")
Mark collider as sensor (no forces)
Marks the collider as a sensor: it detects overlaps but does not generate contact forces.
world.collider_set_sensor(trigger_col, true)
Check if collider is a sensor
Returns true if the collider is configured as a sensor.
if world.collider_is_sensor(trigger_col) {
print("this is a trigger volume")
}
Set collider density
Sets the density, which affects the parent body's mass.
world.collider_set_density(ball_col, 2.0)
Remove a collider from the world
Removes a collider from the world.
world.collider_remove(ball_col)
Destroy the physics world
Destroys the physics world and releases its resources.
world.close()