diff --git a/debug.html b/debug.html index 742e856..c79ae55 100644 --- a/debug.html +++ b/debug.html @@ -5,7 +5,7 @@ diff --git a/debug.ts b/debug.ts index 63f325e..19908a0 100644 --- a/debug.ts +++ b/debug.ts @@ -1,3 +1,3 @@ -import { TickDebug, OrbitDemo } from "./debug/tick"; +import { TickDebug } from "./debug/tick"; -Object.assign(globalThis, { TickDebug, OrbitDemo }); +Object.assign(globalThis, { TickDebug }); diff --git a/debug/tick.ts b/debug/tick.ts index 3e0c44b..320d249 100644 --- a/debug/tick.ts +++ b/debug/tick.ts @@ -1,4 +1,4 @@ -import { canvas2d, h } from "../lib/html"; +import { h } from "../lib/html"; import { Cancel } from "../lib/source"; import { tick } from "../lib/tick"; @@ -34,86 +34,3 @@ export function TickDebug() { 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")]; -} diff --git a/orbit.html b/orbit.html new file mode 100644 index 0000000..591fabe --- /dev/null +++ b/orbit.html @@ -0,0 +1,11 @@ + + + Orbit Simulation + + + + + + diff --git a/orbit.ts b/orbit.ts new file mode 100644 index 0000000..9229d4c --- /dev/null +++ b/orbit.ts @@ -0,0 +1,90 @@ +import { canvas2d, h } from "./lib/html"; +import { Cancel } from "./lib/source"; +import { tick } from "./lib/tick"; + +type Mass = { + x: number; + y: number; + vx: number; + vy: number; + radius: number; + mass: number; + color: string; +}; + +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: Mass[] = []; + + 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, radius: 10, mass: 1000, color: "yellow" }, + { x: -150, y: 150, vx: 130, vy: 130, radius: 9, mass: 10, color: "red" }, + { x: -450, y: 0, vx: 0, vy: 120, radius: 4, mass: 5, color: "#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.mass) / 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, radius, color }) => { + cx.fillStyle = color; + cx.beginPath(); + cx.arc(x + vx * dt, y + vy * dt, radius, 0, Math.PI * 2); + cx.fill(); + }); + break; + } + }); + }; + + const end = () => cancel?.(); + + const start = h("button", { onclick: begin }, "Begin / Reset"); + const stop = h("button", { onclick: end }, "Cease"); + + return [h("h1", {}, "Orbit Simulation"), h("p", {}, start, stop), canvas]; +} + +Object.assign(globalThis, { OrbitDemo });