/// const ws = new WebSocket("/events") type Packet = "tick" | { pos: { id: number, x: number, y: number } } | { game: { width: number, height: number } } | { player: { id: number, name: string } } class Snake { parts: { x: number, y: number, dx: number, dy: number }[] = [] constructor(public name: string) { } add_part(x: number, y: number) { if (!this.parts.length) return this.parts.push({ x, y, dx: 0, dy: 0 }) const last = this.parts[this.parts.length - 1] let dx = x - last.x, dy = y - last.y; if (x > last.x + 1 || x < last.x - 1) dx *= -1, dx /= Math.abs(dx) if (y > last.y + 1 || y < last.y - 1) dy *= -1, dy /= Math.abs(dy) this.parts.push({ x, y, dx, dy }) console.log(this.parts); } } let size = 0 let snakes = new Map() let canvas: HTMLCanvasElement let ctx: CanvasRenderingContext2D document.addEventListener("DOMContentLoaded", () => { canvas = document.createElement("canvas") ctx = canvas.getContext("2d")! document.body.append(canvas) canvas.width = 1000; canvas.height = 1000; redraw() }) function redraw() { ctx.fillStyle = "black" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.save() const scale = canvas.width / size ctx.scale(scale, scale) for (let x = 0; x < size; x++) { for (let y = 0; y < size; y++) { ctx.strokeStyle = "grey" ctx.lineWidth = 0.02 ctx.strokeRect(x, y, 1, 1) } } ctx.translate(0.5, 0.5) for (const [xo, yo] of [[0, 0], [-size, 0], [size, 0], [0, -size], [0, size]]) { ctx.save() ctx.translate(xo, yo) for (const snake of snakes.values()) { ctx.beginPath(); for (let i = 0; i < snake.parts.length; i++) { const p = snake.parts[i]; ctx.moveTo(p.x - p.dx, p.y - p.dy) ctx.lineTo(p.x, p.y) } ctx.lineCap = "round" ctx.lineJoin = "round" ctx.lineWidth = 0.6; ctx.strokeStyle = "red" ctx.stroke() } ctx.restore() } ctx.restore() requestAnimationFrame(redraw) } ws.onerror = console.error ws.onmessage = message => { const p = JSON.parse(message.data) as Packet console.log(p); if (p == "tick") { } else if ("game" in p) { snakes.clear() size = p.game.width } else if ("player" in p) { snakes.set(p.player.id, new Snake(p.player.name)) } else if ("pos" in p) { snakes.get(p.pos.id)?.add_part(p.pos.x, p.pos.y) } }