tuxman/client/js/gfx/map.js

303 lines
8.5 KiB
JavaScript

import { ItemType, get_item_key } from "../logic.js";
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 = "/img/wall_empty.png"
class_name = ""
break
case Direction.WALL_HZ:
image_src = "/img/wall_straight.png"
class_name = ""
break
case Direction.WALL_VT:
image_src = "/img/wall_straight.png"
class_name = "rotate90"
break
case Direction.TURN_Q1:
image_src = "/img/wall_turn.png"
class_name = ""
break
case Direction.TURN_Q2:
image_src = "/img/wall_turn.png"
class_name = "rotate270"
break
case Direction.TURN_Q3:
image_src = "/img/wall_turn.png"
class_name = "rotate180"
break
case Direction.TURN_Q4:
image_src = "/img/wall_turn.png"
class_name = "rotate90"
break
case Direction.TEE_NORTH:
image_src = "/img/wall_tee.png"
class_name = "rotate180"
break
case Direction.TEE_EAST:
image_src = "/img/wall_tee.png"
class_name = "rotate270"
break
case Direction.TEE_SOUTH:
image_src = "/img/wall_tee.png"
class_name = ""
break
case Direction.TEE_WEST:
image_src = "/img/wall_tee.png"
class_name = "rotate90"
break
case Direction.CROSS:
image_src = "/img/wall_cross.png"
class_name = ""
break
case Direction.DOT:
image_src = "/img/wall_dot.png"
class_name = ""
break
case Direction.WALL_END_NORTH:
image_src = "/img/wall_end.png"
class_name = ""
break;
case Direction.WALL_END_EAST:
image_src = "/img/wall_end.png"
class_name = "rotate90"
break;
case Direction.WALL_END_SOUTH:
image_src = "/img/wall_end.png"
class_name = "rotate180"
break;
case Direction.WALL_END_WEST:
image_src = "/img/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) == 1
let south = get_point(width, height, data, x, y+1) == 1
let east = get_point(width, height, data, x+1, y) == 1
let west = get_point(width, height, data, x-1, y) == 1
let current = get_point(width, height, data, x, y) == 1
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])
}
}
}
const gen_items = (map) => {
let width = map.width
let height = map.height
let items = {}
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let tile = get_point(width, height, map.data, x, y)
if (tile != 0) continue
let item_key = get_item_key(x, y, width)
items[item_key] = {type: ItemType.DOT, pos: [x, y]}
let tile_south = get_point(width, height, map.data, x, y + 1)
if (tile_south == 0) {
item_key = get_item_key(x, y + .5, width)
items[item_key] = {type: ItemType.DOT, pos: [x, y + .5]}
}
let tile_east = get_point(width, height, map.data, x + 1, y)
if (tile_east == 0) {
item_key = get_item_key(x + .5, y, width)
items[item_key] = {type: ItemType.DOT, pos: [x + .5, y]}
}
}
}
return items
}
export class Map {
static data
static walls
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)
this.items = gen_items(this)
this.visible = false
}
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)
this.visible = true
}
hide() {
let container = document.getElementById("container")
if (container) container.remove()
let style = document.getElementById("style")
if (style) style.remove()
this.visible = false
}
}