better map bg renderer

This commit is contained in:
Freya Murphy 2023-06-15 17:17:48 -04:00
parent cd10bd2cec
commit 9e43bcbfe9
15 changed files with 99 additions and 82 deletions

View file

@ -72,6 +72,16 @@ input {
margin-bottom: .215rem; margin-bottom: .215rem;
} }
#container img {
image-rendering: pixelated;
}
#canvas {
position: absolute;
width: 100%;
height: 100%;
}
#fps { #fps {
position: absolute; position: absolute;
left: 0; left: 0;

BIN
client/img/pac.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,004 B

BIN
client/img/wall_atlas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -1,9 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<link rel="stylesheet" href="/css/main.css"/> <link rel="stylesheet" href="css/main.css"/>
</head> </head>
<body> <body>
<img src="img/wall_atlas.png" id="atlas" style="display: none;"/>
<div id="container" style="display: none;">
<canvas id="canvas" style="display: none;"></canvas>
</div>
<style id="style"></style>
<div id="center"> <div id="center">
<div id="fps"></div> <div id="fps"></div>
<form id="join" autocomplete="off"> <form id="join" autocomplete="off">
@ -16,8 +21,7 @@
<div id="players"></div> <div id="players"></div>
<input type="button" id="start" value="Start Game"/> <input type="button" id="start" value="Start Game"/>
</div> </div>
<canvas id="can"></canvas>
</div> </div>
<script src="/js/main.js" type="module"></script> <script src="js/main.js" type="module"></script>
</body> </body>
</html> </html>

View file

@ -20,6 +20,12 @@ const draw_players = (data, players, sprites) => {
sprites[id].rotate(180) sprites[id].rotate(180)
break break
} }
if (data.players[id].moving) {
sprites[id].set_img("img/pac.gif")
} else {
sprites[id].set_img("img/pac.png")
}
} }
} }
@ -34,7 +40,7 @@ const update_player_sprites = (data, players, sprites) => {
new_sprites.fill(undefined) new_sprites.fill(undefined)
for (let id of players) { for (let id of players) {
let sprite = new Sprite("/img/pac.png", data.map) let sprite = new Sprite("img/pac.png", data.map)
sprite.layer(3) sprite.layer(3)
sprite.resize(1,1) sprite.resize(1,1)
sprite.show() sprite.show()
@ -45,7 +51,7 @@ const update_player_sprites = (data, players, sprites) => {
} }
const create_map_dot = (data, x, y) => { const create_map_dot = (data, x, y) => {
let dot = new Sprite("/img/dot.png", data.map) let dot = new Sprite("img/dot.png", data.map)
dot.move(x, y) dot.move(x, y)
dot.resize(.2,.2) dot.resize(.2,.2)
dot.show() dot.show()

View file

@ -1,6 +1,6 @@
import { ItemType, get_item_key } from "../logic.js"; import { ItemType, get_item_key } from "../logic.js";
const gen_style = (map, style) => { const update_style = (map, style) => {
const css = ` const css = `
* { * {
--scale: 100; --scale: 100;
@ -18,13 +18,6 @@ const gen_style = (map, style) => {
vertical-align: top; vertical-align: top;
line-height: 0; 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}) { @media (max-aspect-ratio: ${map.width}/${map.height}) {
#container { #container {
@ -58,86 +51,87 @@ const Direction = {
WALL_END_WEST: 16 WALL_END_WEST: 16
} }
const place_tile = (container, type) => { /**
* @param {CanvasRenderingContext2D} context
*/
const draw_tile = (context, x, y, w, type) => {
const img = document.createElement("img") let atlas_index, rotation;
let image_src, class_name;
switch(type) { switch(type) {
case Direction.EMPTY: case Direction.EMPTY:
image_src = "/img/wall_empty.png" return
class_name = ""
break
case Direction.WALL_HZ: case Direction.WALL_HZ:
image_src = "/img/wall_straight.png" atlas_index = [1, 1]
class_name = "" rotation = 0
break break
case Direction.WALL_VT: case Direction.WALL_VT:
image_src = "/img/wall_straight.png" atlas_index = [1, 1]
class_name = "rotate90" rotation = 90
break break
case Direction.TURN_Q1: case Direction.TURN_Q1:
image_src = "/img/wall_turn.png" atlas_index = [2, 0]
class_name = "" rotation = 0
break break
case Direction.TURN_Q2: case Direction.TURN_Q2:
image_src = "/img/wall_turn.png" atlas_index = [2, 0]
class_name = "rotate270" rotation = 270
break break
case Direction.TURN_Q3: case Direction.TURN_Q3:
image_src = "/img/wall_turn.png" atlas_index = [2, 0]
class_name = "rotate180" rotation = 180
break break
case Direction.TURN_Q4: case Direction.TURN_Q4:
image_src = "/img/wall_turn.png" atlas_index = [2, 0]
class_name = "rotate90" rotation = 90
break break
case Direction.TEE_NORTH: case Direction.TEE_NORTH:
image_src = "/img/wall_tee.png" atlas_index = [1, 0]
class_name = "rotate180" rotation = 180
break break
case Direction.TEE_EAST: case Direction.TEE_EAST:
image_src = "/img/wall_tee.png" atlas_index = [1, 0]
class_name = "rotate270" rotation = 270
break break
case Direction.TEE_SOUTH: case Direction.TEE_SOUTH:
image_src = "/img/wall_tee.png" atlas_index = [1, 0]
class_name = "" rotation = 0
break break
case Direction.TEE_WEST: case Direction.TEE_WEST:
image_src = "/img/wall_tee.png" atlas_index = [1, 0]
class_name = "rotate90" rotation = 90
break break
case Direction.CROSS: case Direction.CROSS:
image_src = "/img/wall_cross.png" atlas_index = [0, 0]
class_name = "" rotation = 0
break break
case Direction.DOT: case Direction.DOT:
image_src = "/img/wall_dot.png" atlas_index = [2, 1]
class_name = "" rotation = 0
break break
case Direction.WALL_END_NORTH: case Direction.WALL_END_NORTH:
image_src = "/img/wall_end.png" atlas_index = [0, 1]
class_name = "" rotation = 0
break; break;
case Direction.WALL_END_EAST: case Direction.WALL_END_EAST:
image_src = "/img/wall_end.png" atlas_index = [0, 1]
class_name = "rotate90" rotation = 90
break; break;
case Direction.WALL_END_SOUTH: case Direction.WALL_END_SOUTH:
image_src = "/img/wall_end.png" atlas_index = [0, 1]
class_name = "rotate180" rotation = 180
break; break;
case Direction.WALL_END_WEST: case Direction.WALL_END_WEST:
image_src = "/img/wall_end.png" atlas_index = [0, 1]
class_name = "rotate270" rotation = 270
break; break;
} }
img.setAttribute("class", class_name) let atlas = document.getElementById("atlas")
img.setAttribute("src", image_src) context.save()
context.translate((x+.5)*w, (y+.5)*w)
container.appendChild(img) context.rotate(rotation * Math.PI / 180)
context.drawImage(atlas, atlas_index[0]*w, atlas_index[1]*w, w, w, -w/2, -w/2, w, w)
context.restore()
} }
const get_point = (width, height, data, x, y) => { const get_point = (width, height, data, x, y) => {
@ -209,10 +203,11 @@ const gen_walls = (width, height, data) => {
return walls return walls
} }
const gen_map = (map, container) => { const update_canvas = (map, canvas) => {
let context = canvas.getContext("2d");
for (let y = 0; y < map.height; y++) { for (let y = 0; y < map.height; y++) {
for (let x = 0; x < map.width; x++) { for (let x = 0; x < map.width; x++) {
place_tile(container, map.walls[y * map.width + x]) draw_tile(context, x, y, map.tile_width, map.walls[y * map.width + x])
} }
} }
} }
@ -256,47 +251,42 @@ export class Map {
constructor(width, height, data) { constructor(width, height, data) {
let last = document.getElementById("container")
if (last) last.remove()
this.width = width this.width = width
this.height = height this.height = height
this.data = data this.data = data
this.walls = gen_walls(width, height, data) this.walls = gen_walls(width, height, data)
this.items = gen_items(this) this.items = gen_items(this)
this.visible = false this.visible = false
this.tile_width = 32
canvas.width = this.width * this.tile_width
canvas.height = this.height * this.tile_width
} }
show() { show() {
this.hide()
let container = document.getElementById("container") let container = document.getElementById("container")
if (!container) { container.style.display = ""
container = document.createElement("div")
container.id = "container" let canvas = document.getElementById("canvas")
document.body.appendChild(container) canvas.style.display = ""
}
gen_map(this, container)
let style = document.getElementById("style") let style = document.getElementById("style")
if (!style) {
style = document.createElement("style") update_canvas(this, canvas)
style.id = "style" update_style(this, style)
document.body.appendChild(style)
}
gen_style(this, style)
this.visible = true this.visible = true
} }
hide() { hide() {
let container = document.getElementById("container")
if (container) container.remove() let canvas = document.getElementById("canvas")
let style = document.getElementById("style") canvas.style.display = "none"
if (style) style.remove() container.style.display = "none"
this.visible = false this.visible = false
} }

View file

@ -47,6 +47,10 @@ export class Sprite {
this.#update_pos() this.#update_pos()
} }
set_img(src) {
this.element.src = src
}
rotate(d) { rotate(d) {
this.d = d this.d = d
this.#update_pos() this.#update_pos()

View file

@ -27,7 +27,7 @@ export const ItemType = {
* *
* @typedef {{[key: number]: Key}} InputMap * @typedef {{[key: number]: Key}} InputMap
* *
* @typedef {{pos: Vec2, move_rot: Rotation, input_rot: Rotation, name?: string}} Player * @typedef {{pos: Vec2, move_rot: Rotation, input_rot: Rotation, moving: boolean, name?: string}} Player
* @typedef {{start: boolean, key: Key, name?: string}} PlayerInput * @typedef {{start: boolean, key: Key, name?: string}} PlayerInput
* @typedef {{players: {[key: number]: PlayerInput}, added?: number[], removed?: number[] }} Input * @typedef {{players: {[key: number]: PlayerInput}, added?: number[], removed?: number[] }} Input
* *
@ -96,7 +96,8 @@ function processInput(pastData, input) {
data.input[added] ||= { data.input[added] ||= {
pos: [1, 1], pos: [1, 1],
input_rot: Rotation.EAST, input_rot: Rotation.EAST,
mov_rot: Rotation.EAST mov_rot: Rotation.EAST,
moving: false
}; };
if(!(added in data.players)) { if(!(added in data.players)) {
data.players[added] = structuredClone(data.input[added]) data.players[added] = structuredClone(data.input[added])
@ -314,8 +315,10 @@ const update_players = (data) => {
let tile_in_front = get_tile_with_rot(data.map, current_pos, move_dir) let tile_in_front = get_tile_with_rot(data.map, current_pos, move_dir)
if (tile_in_front != 1 && tile_in_front != 2) { if (tile_in_front != 1 && tile_in_front != 2) {
data.players[id].pos = move_pos data.players[id].pos = move_pos
data.players[id].moving = true
} else { } else {
data.players[id].pos = round_pos(current_pos) data.players[id].pos = round_pos(current_pos)
data.players[id].moving = false
} }
// eat items // eat items