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:

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
}