Skip to content

Collisions & triggers

Solid colliders block and report collisions; sensor colliders overlap and fire trigger callbacks
Solid contacts report collisions; sensor overlaps fire triggers.

createCollisionSystem(rapierWorld, eventQueue) (packages/engine/src/physics/collision-system.ts) drains Rapier’s event queue once per tick, in postPhysics. Register a handler:

const collisions = createCollisionSystem(rapierWorld, eventQueue);
collisions.onCollision((handleA, handleB, started) => {
// started === true on contact begin, false on contact end
});
// each postPhysics: collisions.drain();

A handler receives the two collider handles and a started boolean. Events are buffered first, then handlers run after the drain — so it’s safe to create/destroy bodies inside a handler without corrupting Rapier’s iteration. Resolve a handle back to its entity with physics.getByColliderHandle(handle) (see the registry).

createTriggerDispatch(...) (packages/engine/src/physics/trigger-dispatch.ts) builds a collision handler that turns sensor overlaps into component callbacks. It is registered once via collisions.onCollision(createTriggerDispatch(...)). For each sensor-involved overlap it resolves both collider handles to their Object3Ds and calls, on each side’s GameComponents:

  • onTriggerEnter(other, ctx) when started is true;
  • onTriggerExit(other, ctx) when started is false.

other is the other entity’s Object3D. Only sensor-involved overlaps dispatch triggers — solid-vs-solid contacts are ordinary collisions, not triggers.

The running scene showing colliders interacting under the physics debug overlay
Colliders interacting at runtime (debug overlay on).