FERRETGame engine over Babylon.js
Ferret

Cookbook: structures, ropes and breaking

The guides behind these: strength, stretch, explosions, impact. Each recipe says what to build and what to expect; the runnable versions, with the numbers they must produce, are in tests/unit/examples/physics-cookbook-structures-and-ropes.test.ts.

1. What load does this rope hold?#

A rope link breaks at breakStrain. The strength of a rope held still is breakStrain × E × area; with E = 1e7, A = 1e-4 and breakStrain = 0.25 that is 250 N, about 25 kg.

const rope = cap.rope({ from: [0, 0, 0], to: [0, -2, 0], segments: 8, mass: 0.5, E: 1e7, area: 1e-4,
                        damping: 30, anchorA: anchor, radius: 0.02, breakStrain: 0.25 });
const load = rope.beads[rope.beads.length - 1];
load.mass = kg; load.invMass = 1 / kg;

Hang 10 kg (98 N, a strain of 0.1) and it holds; hang 400 kg and it parts. A load dropped onto the rope breaks it sooner, because the peak force exceeds the weight.

Put a constraint with a known maxForce in series with the expensive part. When the load becomes dangerous the pin goes, and the part is saved.

const pin   = cap.joint({ type: 'rod', a: anchor, b: mid,  maxForce: 1500 });
const chain = cap.joint({ type: 'rod', a: mid,    b: load, maxForce: 6000 });
world.events.on('physics:joint-break', (e) => { /* e.constraint is pin or chain */ });

Raise the load slowly: the pin goes first and the strong link survives. Shear pins in a drive line, break-away signposts, a frangible bolt on a stage: the same idea. Report physics:joint-break to the player ("the tow rope snapped").

3. A crate that breaks only at speed#

Damage is the impulse above a threshold, so a gentle brush does nothing and a hard hit breaks it into pieces. The threshold is the toughness config, the number of pieces is pieces:

host.config('strength').set('world', 'toughness', 10);      // absorbs 10 N s
host.config('strength').set('world', 'pieces', 5);
world.events.on('physics:break', (e: BreakEvent) => { /* e.pieces */ });

A 1 kg crate hitting a wall at 3 m/s gives 3 N s, below the 10 N s it absorbs, and survives; at 20 m/s it gives 20 N s and breaks into five pieces, one physics:break event. Per-kind toughness is a config value at entity or zone scope: host.config('strength').set('entity', 'toughness', 3, 'glass-pane'). See the strength guide for threshold, scale and maxPieces.

4. A bungee that springs back#

Elastic up to yieldStrain, so it returns to its rest length. Past yield it takes a permanent set; past breakStrain it snaps.

const r = cap.rope({ from: [0, 0, 0], to: [0, -2, 0], segments: 8, mass: 0.2, E: 2e5, area: 1e-4, damping: 8,
                     anchorA: anchor, radius: 0.02, yieldStrain: 3, breakStrain: 6 });

A 2 kg jumper stretches below the rest length and settles at F L / (E A) longer than it. Raise the weight, or lower E, to see the lowest point drop; set yieldStrain: 0.002 for a copper wire that stays bent. Events stretch:yield and stretch:break carry the link's name; name the links you care about.

5. A wall that breaks under a blast#

A body takes a push I · A from the blast and breaks when the impulse per area passes its rupture value. Set rupture low for a plasterboard partition, high for a bunker wall, and the same charge breaks one and not the other.

const impulse = blastAt(8, 10).impulse;                                     // per m², 10 kg TNT at 8 m
host.config('explosion').set('entity', 'rupture', impulse * 0.5, plaster.id);
host.config('explosion').set('entity', 'rupture', impulse * 4,   bunker.id);
blast.detonate({ at: [0, 0, 0], tnt: 10 });

Both bodies are 8 m from the charge. The blast is the same; the materials differ: the partition breaks, the bunker wall holds. The entity-scope values are keyed by entity id here; in a game you set them per material kind from the level data.

6. A curtain that hangs and drapes#

Cloth is position-based dynamics with a strain limit; a pinned top row makes a curtain, colliders make it drape:

const curtain = new Cloth({ nu: 20, nv: 20, spacing: 0.05, mass: 0.4, pinned: 'top', origin: [0, 0, 0],
                            u: [1, 0, 0], v: [0, -1, 0], strainLimit: 1.05, iterations: 6, substeps: 2 });
curtain.step(1 / 60);

tarp.colliders.push({ type: 'sphere', center: [0, 0.5, 0], radius: 0.3 }, { type: 'plane', normal: [0, 1, 0], offset: 0 });

The curtain hangs about a metre and the strain limit holds. A tarp dropped over a sphere catches on the top of it. A curtain of 400 particles costs well under a millisecond a step; keep cloth to a handful on screen and see stretch for the budget.