diff --git a/agar.html b/agar.html new file mode 100644 index 0000000..65362d7 --- /dev/null +++ b/agar.html @@ -0,0 +1,40 @@ + + + + + + Test + + + +
+ +
+ + + diff --git a/agar.ts b/agar.ts new file mode 100644 index 0000000..15891a9 --- /dev/null +++ b/agar.ts @@ -0,0 +1,80 @@ +import { drawCircle, fillCircle, resizeCanvas } from "./common.js"; +import Vec2d from "./vec.js"; + +const INITIAL_RADIUS = 100; +const MAX_SPEED = 300; + +let lastTime: number | undefined = undefined; + +// state +let velocity = Vec2d.fromPoint({ x: 0, y: 0 }); +let pos = Vec2d.fromPoint({ x: 0, y: 0 }); +let radius = INITIAL_RADIUS; +let blobs: Vec2d[] = []; + +function update(ctx: CanvasRenderingContext2D, timestamp: number) { + if (lastTime == null) lastTime = timestamp; + const dt = (timestamp - lastTime) / 1000; // s + lastTime = timestamp; + + // update + pos = pos.add(velocity.scale(dt)); + // check collisions + for (let i = blobs.length - 1; i >= 0; i--) { + const blob = blobs[i]; + if (blob.distance(pos) < radius) { + // merge blobs areas + const new_area = Math.PI * radius ** 2 + Math.PI * 10 ** 2; + // compute radius from new area + radius = Math.sqrt(new_area / Math.PI); + blobs.splice(i, 1); + } + } + + // drawing + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + // world space to screen space: always put (pos.x, pos.y) at the center of the screen + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(INITIAL_RADIUS / radius, INITIAL_RADIUS / radius); + ctx.translate(-pos.x, -pos.y) + for (const pos of blobs) { + fillCircle(ctx, pos, 10, 0x00ff00); + } + fillCircle(ctx, pos, radius, 0xff00ff); + // Reset current transformation matrix to the identity matrix + ctx.setTransform(1, 0, 0, 1, 0, 0); + window.requestAnimationFrame((t) => update(ctx, t)); +} + +window.onload = () => { + const canvas = document.getElementById("canvas") as HTMLCanvasElement; + if (canvas == null) throw new Error("Canvas not found") + const ctx = canvas.getContext("2d") as CanvasRenderingContext2D; + if (ctx == null) throw new Error("Canvas context not found") + resizeCanvas(ctx); + + canvas.onmousemove = (e) => { + const rect = canvas.getBoundingClientRect(); + // mouse coordinates relative to canvas + const mouse = Vec2d.fromPoint({ x: e.clientX - rect.left, y: e.clientY - rect.top, }); + const center = Vec2d.fromPoint({ x: canvas.width / 2, y: canvas.height / 2, }); + const max = new Vec2d(MAX_SPEED, MAX_SPEED); + velocity = mouse.sub(center).clamp(max.neg(), max); + }; + + for (let i = 0; i < 10000; ++i) { + const x = (Math.random() - 0.5) * 10000; + const y = (Math.random() - 0.5) * 10000; + blobs.push(new Vec2d(x, y)); + } + + window.requestAnimationFrame((t) => update(ctx, t)); +}; + +window.onresize = () => { + const canvas = document.getElementById("canvas") as HTMLCanvasElement; + if (canvas == null) throw new Error("Canvas not found") + const ctx = canvas.getContext("2d") as CanvasRenderingContext2D; + if (ctx == null) throw new Error("Canvas context not found") + resizeCanvas(ctx); +};