import { canvas2d, h } from "../lib/html"; import { Cancel } from "../lib/source"; import { tick } from "../lib/tick"; export function TickDebug() { const output = h("pre", {}); const tickSource = tick(30); let cancel: Cancel; const begin = () => { // reset / init cancel?.(); output.innerHTML = ""; // subscribe to source, stash cancellation func cancel = tickSource((tick) => { switch (tick[0]) { case "physics": output.append(`${new Date().toISOString()}: Physics\n`); break; case "render": output.append( `${new Date().toISOString()}: Render (dt=${tick[1]})\n` ); break; } }); }; const end = () => cancel?.(); const start = h("button", { onclick: begin }, "Begin"); const stop = h("button", { onclick: end }, "Cease"); return [h("h1", {}, "Tick Event Demo"), start, stop, output, h("hr")]; } export function OrbitDemo() { const [canvas, cx] = canvas2d({ width: 512, height: 512, }); cx.scale(1 / 2, 1 / 2); cx.translate(512, 512); const G = 8000; const PHYSICS_TICKS = 30; const masses: { x: number; y: number; vx: number; vy: number; r: number; m: number; c: string; }[] = []; const tickSource = tick(PHYSICS_TICKS); let cancel: Cancel; const begin = () => { // reset / init cancel?.(); masses.length = 0; masses.push( { x: 0, y: 0, vx: -1, vy: -2, r: 10, m: 1000, c: "yellow" }, { x: -150, y: 150, vx: 130, vy: 130, r: 9, m: 10, c: "red" }, { x: -450, y: 0, vx: 0, vy: 120, r: 4, m: 5, c: "#0f8" } ); // subscribe to source, stash cancellation func cancel = tickSource((tick) => { switch (tick[0]) { case "physics": // apply velocities masses.forEach((mass) => { mass.x += mass.vx * (1 / PHYSICS_TICKS); mass.y += mass.vy * (1 / PHYSICS_TICKS); }); // apply accelerations masses.forEach((mass) => { masses.forEach((other) => { if (mass != other) { const dx = other.x - mass.x; const dy = other.y - mass.y; const rSquared = dx ** 2 + dy ** 2; const f = (G * other.m) / rSquared; const d = Math.sqrt(rSquared); const fx = (f * dx) / d; const fy = (f * dy) / d; mass.vx += fx / PHYSICS_TICKS; mass.vy += fy / PHYSICS_TICKS; } }); }); break; case "render": const [, dt] = tick; cx.fillStyle = "black"; cx.fillRect(-512, -512, 1024, 1024); masses.forEach(({ x, y, vx, vy, r, c }) => { cx.fillStyle = c; cx.beginPath(); cx.arc(x + vx * dt, y + vy * dt, r, 0, Math.PI * 2); cx.fill(); }); break; } }); }; const end = () => cancel?.(); const start = h("button", { onclick: begin }, "Begin"); const stop = h("button", { onclick: end }, "Cease"); return [h("h1", {}, "Orbit Demo"), h("p", {}, start, stop), canvas, h("hr")]; }