const renderLayers = {
foreground: 1 << 0,
};
const gravity = new Vector2(0, -600);
export const createLinearSpringDamperGame = async (): Promise<Game> => {
const { game, world, renderContext, time } = createGame('demo-game');
createCamera(world, {
isStatic: true,
cullingMask: renderLayers.foreground,
verticalWorldUnits: DEMO_VERTICAL_WORLD_UNITS,
});
const physicsWorld = new PhysicsWorld({ gravity });
await createSuspensions(world, renderContext, renderLayers.foreground);
// `createResetEcsSystem`, `createLinearSpringEcsSystem`, and
// `createLinearDamperEcsSystem` must all run before
// `createPhysicsSyncEcsSystem`, which is what steps `physicsWorld`: a
// reset applied (or spring/damper force computed) this tick needs to be
// applied before that step happens (see the Applying Forces guide's
// registration-order caution). `createSpringLineEcsSystem` only needs to
// run before `createRenderEcsSystem`, so its updated line is reflected in
// this tick's render.
world.addSystem(createResetEcsSystem(time));
world.addSystem(createLinearSpringEcsSystem(time));
world.addSystem(createLinearDamperEcsSystem(time));
world.addSystem(createSpringLineEcsSystem());
world.addSystem(createCameraEcsSystem(time));
world.addSystem(createRenderEcsSystem(renderContext));
world.addSystem(createPhysicsSyncEcsSystem(physicsWorld, time));
return game;
};
Both columns hang a wheel below a fixed mount (the attachment point on the vehicle frame) with a LinearSpring, released with an upward velocity to simulate just having hit a bump (the bump kicks the wheel up towards the mount, then the spring pulls it back down), then every few seconds teleported back to that same starting position and velocity to replay the same bump (see reset.component.ts and reset.system.ts; a repeated impulse instead would risk pumping unbounded energy into the undamped column over a long-running demo). The left wheel has only a spring: once disturbed, it keeps oscillating until the next reset, with nothing to dissipate its energy. The right wheel pairs the same spring with a LinearDamper, which resists the compression/extension speed and settles the wheel back to rest well before the next reset, the same role a shock absorber plays alongside a suspension spring. The connecting line's length visualizes each spring's current stretch.