Skip to main content

Collision Events

When two rigid bodies touch, the physics engine reports the contact to both entities. You can respond by playing a sound, applying damage, spawning particles or changing game state. The events are fired on both the collision and the rigidbody components of each entity involved, so you can listen on whichever is more convenient.

Events

EventWhen it firesHandler argument
collisionstartOnce, on the physics step in which two bodies begin touchingContactResult
contactEvery physics step while the bodies remain in contactContactResult
collisionendOnce, when the bodies stop touchingThe other Entity

Contacts are only reported when at least one of the two bodies is dynamic. Static and kinematic bodies never collide with each other. Overlaps with a trigger volume fire triggerenter and triggerleave instead of these events.

Listening for Collisions

Subscribe with on, which returns an EventHandle. Keep that handle and call its off() method when the listener is no longer needed; passing the same callback to off(eventName, callback) on the component, as described in Events, removes the listener too. Use collisionstart for one-off reactions such as an impact sound, and contact when you need the contact details refreshed every step:

const handle = entity.collision.on('collisionstart', (result) => {
console.log(`${entity.name} hit ${result.other.name}`);
});

// Later, when the entity is destroyed or the listener is no longer wanted
handle.off();

Where that code lives depends on how you build:

Subscribe once the entity has its components, as above, or from a Script attached to the entity as shown in the Editor tab. Scripts are covered in the Scripting section.

Contact Data

collisionstart and contact pass a ContactResult with two properties:

  • other - The entity this body collided with.
  • contacts - An array of ContactPoint objects, one for each point where the two shapes touch.

Each contact point holds:

PropertyDescription
pointThe contact point on this entity, in world space
pointOtherThe contact point on the other entity, in world space
localPointThe contact point in the local space of this entity
localPointOtherThe contact point in the local space of the other entity
normalThe contact normal in world space. It points away from the surface of the other entity at the point of contact
impulseThe impulse the physics engine applied to separate the bodies. Larger values mean a harder hit

The impulse is a handy measure of how hard two bodies collided. Use it to scale a sound's volume or the damage dealt, and to ignore glancing touches:

entity.collision.on('collisionstart', (result) => {
let strongest = 0;
for (const contact of result.contacts) {
strongest = Math.max(strongest, contact.impulse);
}
if (strongest > 5) {
entity.sound.play('crash');
}
});

Scene-wide Contacts

To handle every contact in one place, for example in a central audio or damage manager, listen to the contact event on the rigid body component system instead of on individual entities. It fires once per contact point with a SingleContactResult that names both entities:

app.systems.rigidbody.on('contact', (result) => {
// result.a and result.b are the two entities
// result.pointA, result.pointB and result.normal are in world space
if (result.impulse > 5) {
console.log(`${result.a.name} and ${result.b.name} collided hard`);
}
});
tip

contact fires every physics step for as long as two bodies touch, which for a box resting on the floor means every frame. Prefer collisionstart for one-shot effects and keep contact handlers cheap.

See Also