From 6f43c64349891effe59c6ccb038701369ce47126 Mon Sep 17 00:00:00 2001 From: Thibaud Date: Thu, 6 Aug 2026 14:07:33 +0200 Subject: [PATCH] reformat move.ts --- move.ts | 106 +++++++++++++++++++++++--------------------------------- vec.ts | 7 ++++ 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/move.ts b/move.ts index 9c77de7..b22b1d0 100644 --- a/move.ts +++ b/move.ts @@ -4,14 +4,12 @@ import { drawCircle, resizeCanvas } from "./common.js"; const SEGMENT_SPACING = 100; function initTrail(pos: Vec2d, len: number) { - return Array.from({ length: len }, (_, i) => - pos.add(new Vec2d(0, -1).scale(i * SEGMENT_SPACING)), - ); + return Array.from({ length: len }, (_, i) => pos.add(new Vec2d(-1, 0).scale(i * SEGMENT_SPACING))); } // state let target: Vec2d | undefined = undefined; -let trail = initTrail(new Vec2d(200, 200), 5); +let trail = initTrail(new Vec2d(500, 500), 5); let velocity = new Vec2d(500, 500); let pause = false; let mode: "follow" | "bounce" | "circle" = "follow"; @@ -22,27 +20,20 @@ function update(ctx: CanvasRenderingContext2D, timestamp: number) { const dt = (timestamp - lastFrameTime) / 1000; // seconds lastFrameTime = timestamp; if (!pause) { - switch (mode) { - case "bounce": - updateBounce(ctx, dt); - break; - case "follow": - updateFollow(ctx, dt); - break; - case "circle": - updateCircle(ctx, dt); - break; - default: - throw new Error(`Unknown mode: ${mode}`); + switch (mode) { + case "bounce": updateBounce(ctx, dt); break; + case "follow": updateFollow(ctx, dt); break; + case "circle": updateCircle(ctx, dt); break; + default: throw new Error(`Unknown mode: ${mode}`); } } ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); for (const pos of trail) { - drawCircle(ctx, pos, 20, 0xff00ff); + drawCircle(ctx, pos, 20, 0xFF00FF); } - window.requestAnimationFrame((t) => update(ctx, t)); + window.requestAnimationFrame(t => update(ctx, t)); } function updateFollow(ctx: CanvasRenderingContext2D, dt: number) { @@ -52,42 +43,31 @@ function updateFollow(ctx: CanvasRenderingContext2D, dt: number) { // frame, so this is framerate dependent: // trail[0] = trail[0].lerp(target, 0.1); // use exponential decay instead, this is framerate independent: - const alpha = Math.exp(-10 * dt); + // a = a + (b - a) * t lerp formula + // a = a + (b - a) * e^(-k * dt) substitute t with e^(-k * dt) + const alpha = Math.exp(-10 * dt) trail[0] = trail[0].lerp(target, alpha); updateTrail(); } } function updateBounce(ctx: CanvasRenderingContext2D, dt: number) { - // update head pos - // P_t+1 = P_t + V * t - const newPos = trail[0].add(velocity.scale(dt)); - if (newPos.x > ctx.canvas.width - 100) { - velocity.x *= -1; - newPos.x = ctx.canvas.width - 100; - } - if (newPos.y > ctx.canvas.height - 100) { - velocity.y *= -1; - newPos.y = ctx.canvas.height - 100; - } - if (newPos.x < 100) { - velocity.x *= -1; - newPos.x = 100; - } - if (newPos.y < 100) { - velocity.y *= -1; - newPos.y = 100; - } - trail[0] = newPos; - updateTrail(); + // update head pos + // P_t+1 = P_t + V * t + const newPos = trail[0].add(velocity.scale(dt)); + if (newPos.x > ctx.canvas.width - 100) { velocity.x *= -1; newPos.x = ctx.canvas.width - 100; } + if (newPos.y > ctx.canvas.height - 100) { velocity.y *= -1; newPos.y = ctx.canvas.height - 100; } + if (newPos.x < 100) { velocity.x *= -1; newPos.x = 100; } + if (newPos.y < 100) { velocity.y *= -1; newPos.y = 100; } + trail[0] = newPos; + updateTrail(); } function updateCircle(ctx: CanvasRenderingContext2D, dt: number) { const center = new Vec2d(ctx.canvas.width / 2, ctx.canvas.height / 2); - const rel = trail[0].sub(center); - const radius = rel.length(); - const theta = Math.atan2(rel.y, rel.x) + dt; - trail[0] = center.add(Vec2d.fromPolar(radius, theta)); + const rel = trail[0].sub(center); // distance from center + const { r, theta } = rel.toPolar(); + trail[0] = center.add(Vec2d.fromPolar(r, theta + dt)); updateTrail(); } @@ -107,32 +87,32 @@ function updateTrail() { } function init() { - const canvas = document.getElementById("canvas") as HTMLCanvasElement | null; - if (!canvas) throw new Error("unable to get canvas HTML element"); - const ctx = canvas.getContext("2d") as CanvasRenderingContext2D | null; - if (!ctx) throw new Error("unable to get canvas 2D context"); + const canvas = document.getElementById("canvas") as HTMLCanvasElement | null; + if (!canvas) throw new Error("unable to get canvas HTML element"); + const ctx = canvas.getContext("2d") as CanvasRenderingContext2D | null; + if (!ctx) throw new Error("unable to get canvas 2D context"); ctx.canvas.width = ctx.canvas.clientWidth; ctx.canvas.height = ctx.canvas.clientHeight; - canvas.onmousemove = (evt) => { - const { clientX, clientY } = evt; - target = new Vec2d(clientX, clientY); - }; + canvas.onmousemove = (evt) => { + const {clientX, clientY} = evt; + target = new Vec2d(clientX, clientY); + } - canvas.onclick = () => { - pause = !pause; - }; + canvas.onclick = () => { + pause = !pause; + } - window.onkeydown = (evt) => { - if (mode === "bounce") mode = "follow"; - else if (mode === "follow") mode = "circle"; - else if (mode === "circle") mode = "bounce"; - console.log(mode); - }; + window.onkeydown = (evt) => { + if (mode === "bounce") mode = "follow"; + else if (mode === "follow") mode = "circle"; + else if (mode === "circle") mode = "bounce"; + console.log(mode); + } - window.addEventListener("resize", () => resizeCanvas(ctx)); + window.addEventListener('resize', () => resizeCanvas(ctx)); - window.requestAnimationFrame((t) => update(ctx, t)); + window.requestAnimationFrame(t => update(ctx, t)); } init(); diff --git a/vec.ts b/vec.ts index cb1dee8..4e121b7 100644 --- a/vec.ts +++ b/vec.ts @@ -25,6 +25,13 @@ export default class Vec2d implements Point { return `[${this.x}, ${this.y}]`; } + toPolar() { + return { + r: this.length(), + theta: Math.atan2(this.y, this.x), + }; + } + normalize(): Vec2d { const len = this.length(); return new Vec2d(this.x / len, this.y / len);