Skip to main content
← All demos

Wrecking Ball

game.ts
const renderLayers = {
foreground: 1 << 0,
};

export const createWreckingBallGame = async (): Promise<Game> => {
const { game, world, renderContext, time } = createGame('demo-game');

createCamera(world, {
isStatic: true,
cullingMask: renderLayers.foreground,
verticalWorldUnits: DEMO_VERTICAL_WORLD_UNITS,
});

await createWreckingBall(world, renderContext, renderLayers.foreground);

const collisionPairs: CollisionPair[] = [];
const collisionManifolds: CollisionManifold[] = [];
const contactConstraints: ContactConstraint[] = [];

// The revolute joint solver must run after collision resolution so the
// ball's hinge to the crane gets the "last word" on velocity each tick;
// `createArmEcsSystem` only needs to run before `createRenderEcsSystem`,
// so its updated arm is reflected in this tick's render.
world.addSystem(createGravityEcsSystem(time));
world.addSystem(createBroadPhaseEcsSystem(collisionPairs));
world.addSystem(
createNarrowPhaseEcsSystem(collisionPairs, collisionManifolds),
);
world.addSystem(
createCollisionResolutionEcsSystem(
collisionManifolds,
contactConstraints,
time,
),
);
world.addSystem(createRevoluteJointEcsSystem(time));
world.addSystem(createArmEcsSystem());
world.addSystem(createCameraEcsSystem(time));
world.addSystem(createRenderEcsSystem(renderContext));
world.addSystem(createEulerIntegrationEcsSystem(time));

return game;
};

A ball is hinged to a crane by a long arm, pulled back to one side, and released exactly once, when the scene is built, swinging into a wall of bricks. The joint only keeps the ball swinging about the crane's pivot; knocking the wall down comes entirely from the engine's ordinary collision resolution between the ball and the bricks, the same combination of joint and collisions used in the Newton's Cradle demo. After the first swing it's left alone rather than re-launched, so it settles the way a real wrecking ball would after a single push.