summaryrefslogtreecommitdiff
path: root/client/js/gfx
diff options
context:
space:
mode:
Diffstat (limited to 'client/js/gfx')
-rw-r--r--client/js/gfx/graphics.js56
-rw-r--r--client/js/gfx/map.js261
-rw-r--r--client/js/gfx/sprite.js60
3 files changed, 377 insertions, 0 deletions
diff --git a/client/js/gfx/graphics.js b/client/js/gfx/graphics.js
new file mode 100644
index 0000000..e73927e
--- /dev/null
+++ b/client/js/gfx/graphics.js
@@ -0,0 +1,56 @@
+import { Sprite } from './sprite.js'
+import { Rotation } from '../logic.js'
+
+
+export const startGraphicsUpdater = () => {
+
+ let sprites = []
+
+ /**
+ * @type {(data: import("../logic.js").GameState) => void}
+ */
+ return (data) => {
+
+ if (!data.started) return
+
+ let players = Object.keys(data.players).filter(k => data.players[k] !== undefined)
+
+ if (sprites.length !== players.length) {
+
+ for (const sprite of sprites) {
+ if (sprite !== undefined) {
+ sprite.destroy()
+ }
+ }
+
+ sprites = Array(players)
+ sprites.fill(undefined)
+
+ for (let id of players) {
+ let sprite = new Sprite("/static/tux.png", data.map)
+ sprite.show()
+ sprite.resize(1.5,1.5)
+ sprites[id] = sprite
+ }
+ }
+
+ for (let id of players) {
+ let pos = data.players[id].pos
+ sprites[id].move(pos[0], pos[1])
+ switch (data.players[id].move_rot) {
+ case Rotation.NORTH:
+ sprites[id].rotate(270)
+ break
+ case Rotation.EAST:
+ sprites[id].rotate(0)
+ break
+ case Rotation.SOUTH:
+ sprites[id].rotate(90)
+ break
+ case Rotation.WEST:
+ sprites[id].rotate(180)
+ break
+ }
+ }
+ }
+}
diff --git a/client/js/gfx/map.js b/client/js/gfx/map.js
new file mode 100644
index 0000000..0ba7f9c
--- /dev/null
+++ b/client/js/gfx/map.js
@@ -0,0 +1,261 @@
+const gen_style = (map, style) => {
+ const css = `
+ * {
+ --scale: 100;
+ --aspect: ${map.width/map.height};
+ --scaleX: calc(var(--scale) * 1vw);
+ --scaleY: calc(var(--scale) * 1vh);
+ }
+
+ #container {
+ width: calc(var(--scaleY) * var(--aspect));
+ height: var(--scaleY);
+ margin-top: calc((100vh - var(--scaleY))/2);
+ margin-left: calc(50vw - var(--scaleY)*var(--aspect)/2);
+ position: relative;
+ vertical-align: top;
+ line-height: 0;
+ }
+
+ #container img {
+ display: inline-block;
+ width: ${100/map.width}%;
+ height: ${100/map.height}%;
+ image-rendering: pixelated;
+ }
+
+ @media (max-aspect-ratio: ${map.width}/${map.height}) {
+ #container {
+ width: var(--scaleX);
+ height: calc(var(--scaleX) / var(--aspect));
+ margin-left: calc((100vw - var(--scaleX))/2);
+ margin-top: calc(50vh - var(--scaleX)/var(--aspect)/2);
+ }
+ }`;
+
+ style.innerHTML = css
+}
+
+const Direction = {
+ EMPTY: 0,
+ WALL_HZ: 1,
+ WALL_VT: 2,
+ TURN_Q1: 3,
+ TURN_Q2: 4,
+ TURN_Q3: 5,
+ TURN_Q4: 6,
+ TEE_NORTH: 7,
+ TEE_EAST: 8,
+ TEE_SOUTH: 9,
+ TEE_WEST: 10,
+ CROSS: 11,
+ DOT: 12,
+ WALL_END_NORTH: 13,
+ WALL_END_SOUTH: 14,
+ WALL_END_EAST: 15,
+ WALL_END_WEST: 16
+}
+
+const place_tile = (container, type) => {
+
+ const img = document.createElement("img")
+
+ let image_src, class_name;
+ switch(type) {
+ case Direction.EMPTY:
+ image_src = "/static/empty.png"
+ class_name = ""
+ break
+ case Direction.WALL_HZ:
+ image_src = "/static/wall.png"
+ class_name = ""
+ break
+ case Direction.WALL_VT:
+ image_src = "/static/wall.png"
+ class_name = "rotate90"
+ break
+ case Direction.TURN_Q1:
+ image_src = "/static/turn.png"
+ class_name = ""
+ break
+ case Direction.TURN_Q2:
+ image_src = "/static/turn.png"
+ class_name = "rotate270"
+ break
+ case Direction.TURN_Q3:
+ image_src = "/static/turn.png"
+ class_name = "rotate180"
+ break
+ case Direction.TURN_Q4:
+ image_src = "/static/turn.png"
+ class_name = "rotate90"
+ break
+ case Direction.TEE_NORTH:
+ image_src = "/static/tee.png"
+ class_name = "rotate180"
+ break
+ case Direction.TEE_EAST:
+ image_src = "/static/tee.png"
+ class_name = "rotate270"
+ break
+ case Direction.TEE_SOUTH:
+ image_src = "/static/tee.png"
+ class_name = ""
+ break
+ case Direction.TEE_WEST:
+ image_src = "/static/tee.png"
+ class_name = "rotate90"
+ break
+ case Direction.CROSS:
+ image_src = "/static/cross.png"
+ class_name = ""
+ break
+ case Direction.DOT:
+ image_src = "/static/dot.png"
+ class_name = ""
+ break
+ case Direction.WALL_END_NORTH:
+ image_src = "/static/wall_end.png"
+ class_name = ""
+ break;
+ case Direction.WALL_END_EAST:
+ image_src = "/static/wall_end.png"
+ class_name = "rotate90"
+ break;
+ case Direction.WALL_END_SOUTH:
+ image_src = "/static/wall_end.png"
+ class_name = "rotate180"
+ break;
+ case Direction.WALL_END_WEST:
+ image_src = "/static/wall_end.png"
+ class_name = "rotate270"
+ break;
+ }
+
+ img.setAttribute("class", class_name)
+ img.setAttribute("src", image_src)
+
+ container.appendChild(img)
+}
+
+const get_point = (width, height, data, x, y) => {
+ if (x < 0 || x >= width || y < 0 || y >= height) {
+ return 0
+ } else {
+ return data[y * width + x]
+ }
+}
+
+const gen_walls = (width, height, data) => {
+
+ let walls = Array(width * height)
+ for (let y = 0; y < height; y++) {
+ for (let x = 0; x < width; x++) {
+
+ let north = get_point(width, height, data, x, y-1)
+ let south = get_point(width, height, data, x, y+1)
+ let east = get_point(width, height, data, x+1, y)
+ let west = get_point(width, height, data, x-1, y)
+ let current = get_point(width, height, data, x, y)
+
+ let point = Direction.EMPTY
+
+ if (!current) {
+ walls[y * width + x] = point
+ continue
+ }
+
+ if (north && south && east && west) {
+ point = Direction.CROSS
+ } else if (east && west && north) {
+ point = Direction.TEE_NORTH
+ } else if (east && west && south) {
+ point = Direction.TEE_SOUTH
+ } else if (north && south && east) {
+ point = Direction.TEE_EAST
+ } else if (north && south && west) {
+ point = Direction.TEE_WEST
+ } else if (east && west) {
+ point = Direction.WALL_HZ
+ } else if (north && south) {
+ point = Direction.WALL_VT
+ } else if (west && south) {
+ point = Direction.TURN_Q1
+ } else if (south && east) {
+ point = Direction.TURN_Q2
+ } else if (east && north) {
+ point = Direction.TURN_Q3
+ } else if (north && west) {
+ point = Direction.TURN_Q4
+ } else if (north) {
+ point = Direction.WALL_END_NORTH
+ } else if (east) {
+ point = Direction.WALL_END_EAST
+ } else if (south) {
+ point = Direction.WALL_END_SOUTH
+ } else if (west) {
+ point = Direction.WALL_END_WEST
+ } else {
+ point = Direction.DOT
+ }
+
+ walls[y * width + x] = point
+
+ }
+ }
+
+ return walls
+}
+
+const gen_map = (map, container) => {
+ for (let y = 0; y < map.height; y++) {
+ for (let x = 0; x < map.width; x++) {
+ place_tile(container, map.walls[y * map.width + x])
+ }
+ }
+
+}
+
+export class Map {
+
+ constructor(width, height, data) {
+
+ let last = document.getElementById("container")
+ if (last) last.remove()
+
+ this.width = width
+ this.height = height
+ this.data = data
+ this.walls = gen_walls(width, height, data)
+
+ }
+
+ show() {
+ this.hide()
+
+ let container = document.getElementById("container")
+ if (!container) {
+ container = document.createElement("div")
+ container.id = "container"
+ document.body.appendChild(container)
+ }
+
+ gen_map(this, container)
+
+ let style = document.getElementById("style")
+ if (!style) {
+ style = document.createElement("style")
+ style.id = "style"
+ document.body.appendChild(style)
+ }
+
+ gen_style(this, style)
+ }
+
+ hide() {
+ let container = document.getElementById("container")
+ if (container) container.remove()
+ let style = document.getElementById("style")
+ if (style) style.remove()
+ }
+}
diff --git a/client/js/gfx/sprite.js b/client/js/gfx/sprite.js
new file mode 100644
index 0000000..1ed8136
--- /dev/null
+++ b/client/js/gfx/sprite.js
@@ -0,0 +1,60 @@
+export class Sprite {
+
+ constructor(image_src, map) {
+ this.element = document.createElement("img")
+ this.element.src = image_src
+ this.element.className = "sprite"
+ document.getElementById("container").appendChild(this.element)
+
+ this.map = map
+ this.x = 0
+ this.y = 0
+ this.w = 1
+ this.h = 1
+ this.d = 0
+ this.hide()
+ }
+
+ #update_pos() {
+ let width = 100 / this.map.width * this.w
+ let height = 100 / this.map.height * this.h
+ let left = 100 / this.map.width * (this.x + (1 - this.w) / 2)
+ let top = 100 / this.map.height * (this.y + (1 - this.h) / 2)
+
+ this.element.style.width = `${width}%`
+ this.element.style.height = `${height}%`
+ this.element.style.left = `${left}%`
+ this.element.style.top = `${top}%`
+ this.element.style.transform = `rotate(${this.d}deg)`
+ }
+
+ move(x, y) {
+ this.x = x
+ this.y = y
+ this.#update_pos()
+ }
+
+ resize(w, h) {
+ this.w = w
+ this.h = h
+ this.#update_pos()
+ }
+
+ rotate(d) {
+ this.d = d
+ this.#update_pos()
+ }
+
+ hide() {
+ this.element.style.display = "none"
+ }
+
+ show() {
+ this.element.style.display = "initial"
+ }
+
+ destroy() {
+ this.element.remove()
+ }
+
+}