summaryrefslogtreecommitdiff
path: root/client/src/renderer.ts
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/renderer.ts')
-rw-r--r--client/src/renderer.ts320
1 files changed, 320 insertions, 0 deletions
diff --git a/client/src/renderer.ts b/client/src/renderer.ts
new file mode 100644
index 0000000..c7bbbc2
--- /dev/null
+++ b/client/src/renderer.ts
@@ -0,0 +1,320 @@
+import { getMap } from "./map.js";
+import { Items, Players, Rotation, ItemType, Map, Wall, GameState } from "./types.js";
+
+const ATLAS_TILE_WIDTH = 32
+
+const update_style = (width: number, height: number) => {
+
+ let style = document.getElementById("style")
+
+ const css = `
+ * {
+ --scale: 100;
+ --aspect: ${width/height};
+ --scaleX: calc(var(--scale) * 1vw);
+ --scaleY: calc(var(--scale) * 1vh);
+ }
+
+ #canvas {
+ 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;
+ }
+
+ @media (max-aspect-ratio: ${width}/${height}) {
+ #canvas {
+ 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 draw_sprite = (
+ ctx: CanvasRenderingContext2D,
+ x: number,
+ y: number,
+ width: number,
+ atlas: CanvasImageSource,
+ atlas_index: [number, number],
+ atlas_tile_width: number,
+ rotation: Rotation
+) => {
+ ctx.save()
+ ctx.translate(
+ (x + 0.5) * ATLAS_TILE_WIDTH,
+ (y + 0.5) * ATLAS_TILE_WIDTH
+ )
+ ctx.rotate(rotation * Math.PI / 180)
+ ctx.drawImage(
+ atlas,
+ atlas_index[0] * atlas_tile_width,
+ atlas_index[1] * atlas_tile_width,
+ atlas_tile_width,
+ atlas_tile_width,
+ -width * ATLAS_TILE_WIDTH / 2,
+ -width * ATLAS_TILE_WIDTH / 2,
+ width * ATLAS_TILE_WIDTH,
+ width * ATLAS_TILE_WIDTH
+ )
+ ctx.restore()
+}
+
+const draw_players = (
+ ctx: CanvasRenderingContext2D,
+ atlas: CanvasImageSource,
+ players: Players,
+ frame: number
+) => {
+
+ let atlas_frames: [number, number][] = [
+ [0, 2],
+ [1, 2],
+ [2, 2],
+ [0, 3],
+ [1, 3],
+ [0, 3],
+ [2, 2],
+ [1, 2],
+ ]
+
+ for (let id in players) {
+
+ let player = players[id]
+ if (!player) continue
+
+ let atlas_index = atlas_frames[0]
+ if (player.moving) {
+ atlas_index = atlas_frames[Math.floor(frame / 2) % atlas_frames.length]
+ }
+
+ let rotation: number
+ switch (player.moveRotation) {
+ case Rotation.NORTH:
+ rotation = 270
+ break
+ case Rotation.SOUTH:
+ rotation = 90
+ break
+ case Rotation.WEST:
+ rotation = 180
+ break
+ case Rotation.EAST:
+ default:
+ rotation = 0
+ break
+ }
+
+ draw_sprite (
+ ctx,
+ player.pos.x,
+ player.pos.y,
+ 1,
+ atlas,
+ atlas_index,
+ ATLAS_TILE_WIDTH,
+ rotation
+ )
+ }
+}
+
+const draw_items = (
+ ctx: CanvasRenderingContext2D,
+ atlas: CanvasImageSource,
+ items: Items
+) => {
+
+ for (let item_key in items) {
+
+ let item = items[item_key]
+ if (!item) continue
+
+ let width: number, atlas_index: [number, number]
+ switch (item.type) {
+ case ItemType.DOT:
+ width = .2,
+ atlas_index = [2, 3]
+ break
+ default:
+ continue
+ }
+
+ draw_sprite (
+ ctx,
+ item.pos.x,
+ item.pos.y,
+ width,
+ atlas,
+ atlas_index,
+ ATLAS_TILE_WIDTH,
+ 0
+ )
+
+ }
+
+}
+
+const draw_map_canvas = (
+ ctx: CanvasRenderingContext2D,
+ atlas: CanvasImageSource,
+ map: Map
+) => {
+
+ for (let y = 0; y < map.height; y++) {
+ for (let x = 0; x < map.width; x++) {
+
+ let wall_type = map.walls[y * map.width + x]
+
+ let atlas_index: [number, number], rotation: number;
+ switch(wall_type) {
+ case Wall.EMPTY:
+ continue
+ case Wall.WALL_HZ:
+ atlas_index = [1, 1]
+ rotation = 0
+ break
+ case Wall.WALL_VT:
+ atlas_index = [1, 1]
+ rotation = 90
+ break
+ case Wall.TURN_Q1:
+ atlas_index = [2, 0]
+ rotation = 0
+ break
+ case Wall.TURN_Q2:
+ atlas_index = [2, 0]
+ rotation = 270
+ break
+ case Wall.TURN_Q3:
+ atlas_index = [2, 0]
+ rotation = 180
+ break
+ case Wall.TURN_Q4:
+ atlas_index = [2, 0]
+ rotation = 90
+ break
+ case Wall.TEE_NORTH:
+ atlas_index = [1, 0]
+ rotation = 180
+ break
+ case Wall.TEE_EAST:
+ atlas_index = [1, 0]
+ rotation = 270
+ break
+ case Wall.TEE_SOUTH:
+ atlas_index = [1, 0]
+ rotation = 0
+ break
+ case Wall.TEE_WEST:
+ atlas_index = [1, 0]
+ rotation = 90
+ break
+ case Wall.CROSS:
+ atlas_index = [0, 0]
+ rotation = 0
+ break
+ case Wall.DOT:
+ atlas_index = [2, 1]
+ rotation = 0
+ break
+ case Wall.WALL_END_NORTH:
+ atlas_index = [0, 1]
+ rotation = 0
+ break;
+ case Wall.WALL_END_EAST:
+ atlas_index = [0, 1]
+ rotation = 90
+ break;
+ case Wall.WALL_END_SOUTH:
+ atlas_index = [0, 1]
+ rotation = 180
+ break;
+ case Wall.WALL_END_WEST:
+ atlas_index = [0, 1]
+ rotation = 270
+ break;
+ }
+
+ draw_sprite (
+ ctx,
+ x,
+ y,
+ 1,
+ atlas,
+ atlas_index,
+ ATLAS_TILE_WIDTH,
+ rotation
+ )
+ }
+ }
+
+}
+
+let map_canvas = document.createElement("canvas")
+const draw_map = (
+ ctx: CanvasRenderingContext2D,
+ atlas: CanvasImageSource,
+ map: Map,
+ last: number | undefined
+) => {
+
+ if (map.id !== last) {
+ map_canvas.width = map.width * ATLAS_TILE_WIDTH
+ map_canvas.height = map.height * ATLAS_TILE_WIDTH
+
+ let map_ctx = map_canvas.getContext("2d")
+ draw_map_canvas(map_ctx, atlas, map)
+ }
+
+ ctx.drawImage (
+ map_canvas,
+ 0,
+ 0
+ )
+
+}
+
+let last_map_drawn: number | undefined
+export const startGraphicsUpdater = () => {
+
+ let canvas = document.getElementById("canvas") as HTMLCanvasElement
+ let atlas = document.getElementById("atlas") as HTMLImageElement
+
+ /**
+ * @param {import("./logic").GameState} data
+ */
+ return (
+ data: GameState,
+ frame: number
+ ) => {
+
+ let map = getMap(data.mapId)
+
+ if (!map) return
+
+ if (map.id !== last_map_drawn) {
+ canvas.style.display = ""
+ canvas.width = map.width * ATLAS_TILE_WIDTH
+ canvas.height = map.height * ATLAS_TILE_WIDTH
+ }
+
+ let ctx = canvas.getContext("2d")
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
+
+ draw_map(ctx, atlas, map, last_map_drawn)
+ draw_items(ctx, atlas, data.items)
+ draw_players(ctx, atlas, data.players, frame)
+ update_style(map.width, map.height)
+
+ last_map_drawn = map.id
+
+ }
+
+}