How to Implement a Mouse Joint in Planck.js?
This article provides a step-by-step guide on how to implement a Mouse Joint in planck.js, a 2D physics engine for JavaScript. You will learn how to set up the joint, update its target position based on user input (like mouse or touch movements), and properly destroy it when the interaction ends. By the end of this guide, you will be able to allow users to click and drag physics bodies smoothly within your simulation.
Understanding the Mouse Joint
In planck.js (a rewrite of Box2D), a MouseJoint is used
to manipulate a physics body using the cursor or a touch point. Instead
of instantly teleporting an object to the mouse coordinates—which breaks
physics laws and causes collisions to glitch—the Mouse Joint acts like a
stiff spring. It applies forces to pull the target body toward the
cursor’s position while maintaining realistic physical interactions with
other objects.
Step 1: Initial Setup and Requirements
To create a Mouse Joint, you need a reference to your planck.js
World instance, a “ground” or dummy body (usually an empty
static body), and the dynamic body that the user wants to drag.
// A static ground body is required as the first body for the joint
const groundBody = world.createBody();
// Variable to store the active joint
let mouseJoint = null;Step 2: Creating the Joint on Mouse Down
When the user clicks or touches a physics body, you need to calculate
the world coordinates of the click and initialize the
MouseJointDef.
function onMouseDown(mouseWorldX, mouseWorldY, targetBody) {
if (mouseJoint) return; // Already dragging something
const jointDef = {
bodyA: groundBody, // The static ground body
bodyB: targetBody, // The dynamic body to drag
target: planck.Vec2(mouseWorldX, mouseWorldY),
maxForce: 1000.0 * targetBody.getMass(), // Force scale based on mass
frequencyHz: 5.0, // Oscillation frequency (stiffness)
dampingRatio: 0.7 // Prevents endless bouncing
};
mouseJoint = world.createJoint(planck.MouseJoint(jointDef));
targetBody.setAwake(true); // Ensure the body is active
}Step 3: Updating the Target Position on Mouse Move
As the user moves their cursor across the screen, you must continuously update the target vector of the Mouse Joint. This tells the physics engine where to pull the body next.
function onMouseMove(mouseWorldX, mouseWorldY) {
if (mouseJoint) {
// Update the joint's target to the new cursor position
mouseJoint.setTarget(planck.Vec2(mouseWorldX, mouseWorldY));
}
}Step 4: Destroying the Joint on Mouse Up
When the user releases the mouse button or lifts their finger, you must destroy the joint to release the object. If you omit this step, the object will remain tethered to that final coordinate indefinitely.
function onMouseUp() {
if (mouseJoint) {
world.destroyJoint(mouseJoint);
mouseJoint = null;
}
}