1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
/// <reference lib="dom" />
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<number, Snake>()
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)
}
}
|