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")];
}