better map bg renderer
|
@ -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
After Width: | Height: | Size: 1,004 B |
BIN
client/img/wall_atlas.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 563 B |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.4 KiB |
|
@ -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>
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|