Hold to thrust
const renderLayers = {
foreground: 1 << 0,
};
export const createTorqueGame = async (): Promise<Game> => {
const { game, world, renderContext, time } = createGame('demo-game');
createCamera(world, {
isStatic: true,
cullingMask: renderLayers.foreground,
verticalWorldUnits: DEMO_VERTICAL_WORLD_UNITS,
});
// No gravity: these flywheels only ever spin in place, so nothing needs
// to pull them downward.
const physicsWorld = new PhysicsWorld({ gravity: Vector2.zero });
const thrustInput = new HoldAction('thrust');
const inputManager = registerInputs(world, time, {
holdActions: [thrustInput],
});
const keyboardInputSource = new KeyboardInputSource(inputManager);
keyboardInputSource.holdBindings.add(
new KeyboardHoldBinding(thrustInput, keyCodes.space),
);
const { x: width, y: height } = calculateVisibleWorldSize(
renderContext.width,
renderContext.height,
DEMO_VERTICAL_WORLD_UNITS,
);
const columnWidth = width / 2;
await createThrusterScenario(
world,
renderContext,
renderLayers.foreground,
new Vector2(-columnWidth / 2, height * 0.1),
thrustInput,
);
await createMotorScenario(
world,
renderContext,
renderLayers.foreground,
new Vector2(columnWidth / 2, height * 0.1),
);
// `createThrusterEcsSystem` and `createGustEcsSystem` change
// `RigidBody.angularVelocity` directly for this tick, and
// `createAngularVelocityMotorEcsSystem` reads/corrects it, so all three
// must run before `createPhysicsSyncEcsSystem`, which is what steps
// `physicsWorld` (see the Applying Forces guide's registration-order
// caution).
world.addSystem(createThrusterEcsSystem(time));
world.addSystem(createGustEcsSystem(time));
world.addSystem(createAngularVelocityMotorEcsSystem(time));
world.addSystem(createCameraEcsSystem(time));
world.addSystem(createRenderEcsSystem(renderContext));
world.addSystem(createPhysicsSyncEcsSystem(physicsWorld, time));
return game;
};
This demo showcases the two ways to spin a RigidBody with torque. On the left, a flywheel carries a demo-specific ThrusterEcsComponent: while Space is held, createThrusterEcsSystem calls RigidBody.applyTorque on it directly every tick, spinning it up, and releasing lets a small angularDrag on the body gradually spin it back down, since nothing drives it once the torque stops. There's no engine-provided component for this one-shot/manual case, a game is expected to write a small system like this itself. On the right, a flywheel carries an AngularVelocityMotorEcsComponent, a built-in engine component that holds a steady target angular velocity on its own, no input needed, with no angularDrag of its own; a demo-only gust periodically knocks its speed off course, and the motor spends its limited maxTorque budget correcting back towards the target every tick afterwards.