How does planck.js handle edge shapes?

Planck.js, a 2D JavaScript physics engine rewritten from LiquidFun/Box2D, handles terrain generation primarily through the use of Edge and Chain shapes. Unlike closed polygons, edge shapes are line segments designed specifically to represent static, hollow environments such as hills, valleys, and platforms. By stringing these segments together, developers can create complex, continuous terrain without the performance overhead or collision glitches associated with overlapping solid shapes.


Understanding Edge and Chain Shapes

In planck.js, terrain is typically constructed using two geometric primitives:

Ghost Vertices and Smooth Collisions

One of the biggest challenges in game physics is the “ghost collision” phenomenon, where a sliding object hits an internal vertex between two perfectly aligned flat surfaces and abruptly stops. Planck.js solves this by utilizing ghost vertices (also known as adjacent vertices).

When you define a chain shape or a series of connected edges, planck.js stores:

The physics solver uses these ghost vertices to calculate smooth collision normals. When a dynamic body (like a player or a wheel) slides across the terrain, the engine anticipates the next segment’s slope, ensuring a seamless transition across the vertices.

Implementing Terrain Generation

To generate a terrain in planck.js, you typically define an array of 2D vectors representing the landscape heights and pass them to a Chain shape.

const world = planck.World();
const groundBody = world.createBody();

// Define vertices for a simple uneven terrain
const vertices = [
  planck.Vec2(0.0, 0.0),
  planck.Vec2(10.0, 2.0),
  planck.Vec2(20.0, 1.0),
  planck.Vec2(30.0, 5.0),
  planck.Vec2(40.0, 0.0)
];

// Create a continuous chain shape for the terrain
groundBody.createFixture(planck.Chain(vertices), {
  density: 0.0,
  friction: 0.6
});

Performance and Collision Limits

Because edge and chain shapes are strictly static primitives, they do not collide with each other and cannot be used for dynamic, moving bodies. This limitation is a deliberate optimization. Because they lack area, planck.js can bypass complex mass and inertia calculations, allowing the engine to handle massive, procedurally generated worlds with thousands of terrain vertices at a minimal performance cost.