How to Simulate Pulley Joints in planck.js?

This article provides a comprehensive guide on how to implement and simulate a pulley joint using planck.js, the 2D physics engine for JavaScript applications. You will learn the core mechanics of how a pulley joint operates, how it calculates and simulates mechanical advantage, and the exact step-by-step code required to configure it in your physics world.

Understanding the Pulley Joint in planck.js

In 2D physics engines like planck.js (which is based on Box2D), a Pulley Joint is used to connect two bodies to two fixed ground anchors. When one body moves up, the other body moves down based on a simulated rope.

Unlike a simple distance joint, a pulley joint allows you to simulate a mechanical advantage (or gear ratio). This means you can make it so that moving Body A by 1 meter causes Body B to move by 2 meters, mimicking a real-world block and tackle system.

The Pulley Joint Equation

The physics engine maintains the total length of the simulated rope using a specific constraint equation. If the ratio is set to \(1.0\), the rope has a \(1:1\) relationship.

The fundamental formula governing the joint’s behavior is:

\[\text{Length}_1 + \text{ratio} \times \text{Length}_2 = \text{constant}\]

Where:

If you set the ratio to \(2.0\), Body 1 will have to move two units for every one unit Body 2 moves. This effectively doubles the simulated force applied to Body 2 from Body 1’s weight.

Step-by-Step Implementation

To create a pulley joint in planck.js, you need two dynamic bodies and two fixed points in the world to serve as the overhead pulleys.

1. Define the Anchors and Bodies

First, you must establish your world coordinates, your two moving bodies, and the two ground anchors where the “pulleys” are mounted.

2. Configure the Joint Definition

You use PulleyJointDef to configure the properties before instantiating the joint in the world.

const planck = require('planck-js');
const world = planck.World();

// ... (Assume bodyA and bodyB are already created dynamic bodies)

// Define ground anchor points (where the pulleys hang from)
const groundAnchorA = planck.Vec2(-4.0, 10.0);
const groundAnchorB = planck.Vec2(4.0, 10.0);

// Define local anchor points on the bodies themselves
const localAnchorA = planck.Vec2(0.0, 0.0);
const localAnchorB = planck.Vec2(0.0, 0.0);

// Set the mechanical advantage ratio
const ratio = 2.0; 

// Create the joint definition
const pulleyJoint = world.createJoint(planck.PulleyJoint({
  groundAnchorA: groundAnchorA,
  groundAnchorB: groundAnchorB,
  bodyA: bodyA,
  bodyB: bodyB,
  localAnchorA: localAnchorA,
  localAnchorB: localAnchorB,
  ratio: ratio
}));

Key Parameters for Tuning

When configuring your pulley joint to get the exact mechanical advantage you need, keep these parameters in mind: