Matter.js Bouncing Grenade Projectile Simulation
Simulating a realistic bouncing grenade in Matter.js requires
configuring the physical properties of both the projectile and the
terrain, properly applying launch forces, and managing collision
restitution. This guide covers how to set up the Matter.js physics
engine, configure the restitution (bounciness) and friction
values to mimic a heavy explosive canister, apply initial velocity and
angular spin, and implement progressive damping so the grenade settles
naturally rather than bouncing perpetually.
Understanding Restitution in Matter.js
In Matter.js, the restitution property defines how much
kinetic energy is retained after a collision, with values ranging from
0 (completely inelastic) to 1 (completely
elastic).
A critical detail of Matter.js is its collision resolution formula:
by default, when two bodies collide, the engine resolves the bounce
using Math.max(bodyA.restitution, bodyB.restitution).
Because of this, giving the ground a restitution of 0.8
will cause every object to bounce high, regardless of its own
properties. For a realistic simulation, keep the ground's restitution
low (between 0.1 and 0.3) and define the
primary bounce characteristics on the grenade itself.
Configuring the Grenade Body
A military fragmentation or smoke grenade is a dense, relatively heavy object. It should bounce significantly on its first impact but rapidly bleed kinetic energy due to metal deformation, ground friction, and mass.
Set the grenade body with the following properties:
const grenade = Matter.Bodies.circle(startX, startY, 10, {
density: 0.004, // Heavier than default to resist light forces
restitution: 0.45, // Moderate bounce
friction: 0.8, // High surface friction to induce rolling
frictionAir: 0.005, // Low air resistance for a parabolic arc
frictionStatic: 1.0, // Prevents sliding once settled
render: {
fillStyle: '#4B5320' // Military olive drab
}
});Setting Up the Ground
Define the ground as a static body with minimal bounciness to ensure the grenade controls the bounce dynamic:
const ground = Matter.Bodies.rectangle(400, 590, 810, 30, {
isStatic: true,
restitution: 0.2,
friction: 0.9
});Launching the Grenade
Launch the grenade by applying an initial velocity vector combined with angular velocity (spin). Applying spin enhances realism because the grenade will kick forward or backward depending on the orientation of its collision with the terrain:
// Launch with an angle and power
const launchAngle = -Math.PI / 4; // 45 degrees upward
const launchSpeed = 15;
Matter.Body.setVelocity(grenade, {
x: Math.cos(launchAngle) * launchSpeed,
y: Math.sin(launchAngle) * launchSpeed
});
// Add rotational spin
Matter.Body.setAngularVelocity(grenade, 0.15);Simulating Realistic Energy Loss on Impact
Pure restitution calculations often leave projectiles feeling floaty
or rubbery. Real grenades lose their bounciness exponentially after each
hit. You can implement progressive energy loss using the
collisionStart event:
Matter.Events.on(engine, 'collisionStart', (event) => {
event.pairs.forEach((pair) => {
const body = pair.bodyA === grenade ? pair.bodyA : (pair.bodyB === grenade ? pair.bodyB : null);
if (body) {
// Decay restitution with each bounce
body.restitution *= 0.6;
// Reduce horizontal slide on hard impacts
Matter.Body.setVelocity(body, {
x: body.velocity.x * 0.7,
y: body.velocity.y
});
// Cut off tiny micro-bounces to let the body sleep
if (Math.abs(body.velocity.y) < 1.5) {
body.restitution = 0;
}
}
});
});This progressive decay ensures the first impact absorbs the majority of the velocity, producing a short second hop and a quick transition into a roll, matching the real-world behavior of heavy ordnance.