Skip to content

Rope and distortion ​

Rope ​

A Rope stretches a texture along a path as a ribbon: cables, tails, trails, lightning, banners. Give it points, or a curve to generate them from.

ts
import { Rope, RopeConfig, RopeCurveMode, Texture } from "willow";

class Cable {
    static main(): void {
        const tex: Texture = Texture.load("assets/cable.png");

        const cfg: RopeConfig = {
            width: 8,
            curveMode: RopeCurveMode.CATENARY,
            start: Vec2{ x: 100.0, y: 100.0 },
            end: Vec2{ x: 600.0, y: 120.0 },
            sag: 80,
            segments: 32,
        };
        const cable: Rope = new Rope(tex, cfg);
        engine.root2d.add(cable);

        let t: float = 0;
        App.onFrame((dt: float): void => {
            t += dt;
            const c: RopeConfig = cable.config;
            c.sag = 80 + Math.sin(t * 2) * 20;
            cable.config = c;
            cable.update();
        });
    }
}
Curve modeShapeUses
LINEStraight from start to end.
CATENARYA hanging cable.sag
QUAD_BEZIERA quadratic curve.control0
CUBIC_BEZIERA cubic curve.control0, control1
WAVEA sine wave along the line.amplitude, frequency, phase

Other options: width, segments (default 20), joinMode (RopeJoinMode.MITER or BEVEL) and color. For a free-form path, pass a flat [x0, y0, x1, y1, ...] array instead of a config, and change it later with setPoints. After changing config, call update() to rebuild the ribbon.

DistortionGrid ​

A DistortionGrid draws a texture as a grid of cols by rows cells whose corners you can push around: ripples, jelly, flags, heat haze.

ts
import { DistortionGrid, Texture } from "willow";

class Flag {
    static main(): void {
        const flag: DistortionGrid = new DistortionGrid(Texture.load("assets/flag.png"), 12, 6);
        flag.setPosition(250, 150);
        engine.root2d.add(flag);

        let t: float = 0;
        App.onFrame((dt: float): void => {
            t += dt;
            for (let col: int = 0; col <= flag.cols; col++) {
                for (let row: int = 0; row <= flag.rows; row++) {
                    const wave: float = Math.sin(t * 4 + col * 0.6) * col * 1.5;
                    flag.setVertex(col, row, 0, wave);
                }
            }
        });
    }
}

setVertex(col, row, dx, dy) offsets one grid corner from its rest position (setPoint is the same call). A grid of cols by rows cells has corners from 0 to cols and 0 to rows. reset() puts every corner back.

Next ​