Trigger Sound on Collision in Matter.js
Triggering a sound effect when two specific bodies collide in
Matter.js requires identifying the interacting physics bodies and
listening for the engine's collision events. By assigning unique labels
to your bodies, monitoring the collisionStart event on the
engine, and playing an audio element when those labels match, you can
seamlessly integrate collision-based audio into your web application or
game.
1. Assign Identifiers to Your Bodies
When creating bodies using Matter.Bodies, assign a
custom label property to each body. This makes it
straightforward to detect which specific objects are interacting during
a collision.
const ball = Matter.Bodies.circle(100, 100, 20, {
label: 'ball'
});
const ground = Matter.Bodies.rectangle(400, 600, 810, 60, {
isStatic: true,
label: 'ground'
});
Matter.Composite.add(engine.world, [ball, ground]);2. Prepare the Audio Element
Load your audio using the standard HTML5 Audio
constructor or an <audio> tag in your HTML.
const bounceSound = new Audio('bounce.mp3');To ensure the sound plays even if the previous playback hasn't
finished, clone the node or reset currentTime to zero
before calling play().
function playBounceSound() {
bounceSound.currentTime = 0;
bounceSound.play().catch(error => {
// Handle browser autoplay policies if triggered before user interaction
console.warn('Audio playback prevented:', error);
});
}3. Listen for the Collision Event
Matter.js provides collision lifecycle events on the
engine object. Use
Matter.Events.on(engine, 'collisionStart', callback) to
intercept the moment two bodies make contact.
Iterate through the event.pairs array and check if the
pair contains the two target labels.
Matter.Events.on(engine, 'collisionStart', (event) => {
const pairs = event.pairs;
for (let i = 0; i < pairs.length; i++) {
const bodyA = pairs[i].bodyA;
const bodyB = pairs[i].bodyB;
// Check if the collision is between 'ball' and 'ground'
const isBallAndGround =
(bodyA.label === 'ball' && bodyB.label === 'ground') ||
(bodyA.label === 'ground' && bodyB.label === 'ball');
if (isBallAndGround) {
playBounceSound();
break;
}
}
});Alternative: Checking by Object Reference
If your bodies are dynamic or you do not want to rely on string labels, you can check directly against the body references:
const isTargetCollision =
(bodyA === ball && bodyB === ground) ||
(bodyA === ground && bodyB === ball);
if (isTargetCollision) {
playBounceSound();
}Velocity-Based Playback (Optional)
To make sounds feel realistic, check the collision's relative
velocity. You can prevent sound playback on very light touches or scale
the audio volume based on impact speed by accessing
pairs[i].collision.depth or the bodies' velocities:
const speedA = Math.hypot(bodyA.velocity.x, bodyA.velocity.y);
const speedB = Math.hypot(bodyB.velocity.x, bodyB.velocity.y);
const relativeSpeed = Math.abs(speedA - speedB);
if (relativeSpeed > 1.5) {
// Scale volume between 0.1 and 1.0 based on impact
bounceSound.volume = Math.min(Math.max(relativeSpeed / 10, 0.1), 1.0);
playBounceSound();
}