agar: add agar.ts
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Test</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000000;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-wrapper {
|
||||||
|
width: 90vw;
|
||||||
|
height: 90vh;
|
||||||
|
border-radius: 16px;
|
||||||
|
background-color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="canvas-wrapper">
|
||||||
|
<canvas id="canvas" tabindex="0"></canvas>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script src="agar.js" type="module"></script>
|
||||||
|
</html>
|
||||||
@@ -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);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user