Grappling Hook Swing Momentum in Matter.js
This article explains how to create realistic swinging momentum for a grappling hook mechanic using the Matter.js 2D physics engine. By configuring distance constraints, tuning body damping and friction, and applying tangential forces during player input, you can replicate authentic pendulum physics and cable-based momentum in your web games.
1. Setting Up the Cable with Matter.Constraint
A grappling hook cable is represented in Matter.js using
Matter.Constraint. This connects the player’s body to an
anchor point in the game world.
To maintain swinging momentum rather than creating an elastic
bouncing effect, set the stiffness high and the
damping low:
const { Bodies, Constraint, World } = Matter;
// Create the player body
const player = Bodies.circle(100, 200, 20, {
density: 0.004,
frictionAir: 0.005 // Lower value preserves swinging momentum
});
// Define the anchor point where the hook hits
const hookPoint = { x: 300, y: 50 };
// Calculate distance between player and hook point
const distance = Matter.Vector.magnitude(
Matter.Vector.sub(player.position, hookPoint)
);
// Create the cable constraint
const cable = Constraint.create({
pointA: hookPoint,
bodyB: player,
length: distance,
stiffness: 0.9, // High stiffness creates a taut cable
damping: 0.01 // Low damping preserves kinetic energy
});
World.add(engine.world, [player, cable]);2. Tuning Air Resistance and Friction
By default, Matter.js bodies have an air resistance
(frictionAir: 0.01) that quickly bleeds momentum, causing a
pendulum swing to come to a halt prematurely.
To simulate authentic swinging:
- Lower
frictionAirwhile attached: Setplayer.frictionAirto a lower value (between0.001and0.005) when the hook is active. - Restore
frictionAirupon release: Returnplayer.frictionAirto standard levels when detaching to prevent uncontrollable floating.
3. Adding Swing Momentum (Pumping the Swing)
In real pendulums, swinging higher requires injecting energy into the system. You can simulate player control by applying a force perpendicular to the cable vector (tangential force).
Inside your game loop, detect input and apply a tangential impulse:
function applySwingForce(direction) {
// Vector from anchor to player
const arm = Matter.Vector.sub(player.position, hookPoint);
// Perpendicular vector for tangential direction
const tangent = Matter.Vector.normalise({
x: -arm.y,
y: arm.x
});
// Determine direction: 1 for clockwise, -1 for counter-clockwise
const forceMagnitude = 0.002 * direction;
const force = Matter.Vector.mult(tangent, forceMagnitude);
Matter.Body.applyForce(player, player.position, force);
}4. Retracting and Extending the Cable
Adjusting the cable length while swinging alters angular velocity naturally due to the conservation of angular momentum (similar to a figure skater pulling in their arms):
// Shorten cable (reel in)
if (reelIn && cable.length > 50) {
cable.length -= 2;
}
// Lengthen cable (reel out)
if (reelOut && cable.length < 500) {
cable.length += 2;
}Shortening the constraint naturally pulls the player closer to the pivot, accelerating their swing speed without requiring artificial velocity modifications.
5. Releasing the Hook
When releasing the grappling hook, remove the constraint from the world. The player's existing linear velocity will carry over automatically, allowing the momentum gathered during the swing to launch them through the air:
function releaseHook() {
World.remove(engine.world, cable);
player.frictionAir = 0.01; // Reset to default air friction
}