How Does Restitution Control Bounciness in Planck.js?

In Planck.js—a 2D JavaScript physics engine based on Box2D—the restitution property directly determines the elasticity, or “bounciness,” of a rigid body during a collision. This article explores how restitution dictates kinetic energy retention, how the engine calculates bouncing behavior when two objects collide, and how to implement it effectively in your code.

Understanding Restitution in Physics Engines

Restitution is a coefficient that represents the ratio of the relative velocity after a collision to the relative velocity before a collision. In Planck.js, this value is defined on a Fixture object rather than the rigid body itself.

The value is typically constrained between 0.0 and 1.0:

Values greater than 1.0 are technically possible in the engine but will add energy to the system, causing the object to bounce higher with each impact, which violates the laws of physics.

How Planck.js Resolves Multi-Object Collisions

When two fixtures collide, Planck.js must determine a single, combined restitution value for the interaction. Because each fixture has its own independent restitution property, the engine uses a specific formula to calculate the outcome.

By default, Planck.js uses the maximum restitution value of the two colliding shapes. The mathematical representation of this combined mixing formula is:

\[k_r = \max(\text{restitution}_1, \text{restitution}_2)\]

For example, if a bouncy ball with a restitution of 0.8 hits a solid concrete floor with a restitution of 0.0, the engine will select 0.8 as the final restitution value, causing the ball to bounce. If you require a different mixing behavior (such as multiplying the values instead), you can override this globally or handle it within the engine’s pre-solve contact listeners.

Code Implementation Example

To apply bounciness to an object in Planck.js, you must set the restitution property inside the fixture definition before attaching it to a body.

const planck = require('planck-js');

// Create a world
const world = planck.World();

// Create a rigid body
const body = world.createBody({
  type: 'dynamic',
  position: planck.Vec2(0, 10)
});

// Define the shape and fixture with restitution
const ballShape = planck.Circle(1.0);
body.createFixture({
  shape: ballShape,
  density: 1.0,
  friction: 0.3,
  restitution: 0.75 // This sets the bounciness to 75% efficiency
});

By adjusting this decimal value on your fixtures, you can easily simulate a wide variety of materials, ranging from heavy, dead weights to highly active, bouncy projectiles.