diff --git a/client/js/main.js b/client/js/main.js
index c80f8f3..7e97bcb 100644
--- a/client/js/main.js
+++ b/client/js/main.js
@@ -17,8 +17,8 @@ lobby.style.display = "none";
join.onsubmit = function (event) {
return __awaiter(this, void 0, void 0, function* () {
event.preventDefault();
- const room_code = this.elements.room_code.value.trim();
- const player_name = this.elements.name.value.trim();
+ const room_code = document.getElementById("room_code").value;
+ const player_name = document.getElementById("player_name").value;
if (room_code == '') {
alert('Please enter a room code');
return;
diff --git a/client/mapeditor.html b/client/mapeditor.html
new file mode 100644
index 0000000..4fca9de
--- /dev/null
+++ b/client/mapeditor.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/src/editor.ts b/client/src/editor.ts
new file mode 100644
index 0000000..687f076
--- /dev/null
+++ b/client/src/editor.ts
@@ -0,0 +1,166 @@
+import { genMap } from "./map.js"
+import { startGraphicsUpdater } from "./renderer.js"
+import { GameState, Vec2, ATLAS_TILE_WIDTH, Tile } from "./types.js"
+
+const mapgen = document.getElementById("mapgen")
+const sidebar = document.getElementById("sidebar")
+sidebar.style.display = "none"
+
+mapgen.onsubmit = async function(event) {
+ event.preventDefault()
+
+ const width_str = (
document.getElementById("width")).value
+ const height_str = (document.getElementById("height")).value
+
+ const width = parseInt(width_str)
+ const height = parseInt(height_str)
+
+ if (!width || width < 3 || !height || height < 3) {
+ alert('Invalid numbers or dimensions too small')
+ return
+ }
+
+ mapgen.style.display = "none"
+
+ runMapEditor(width, height)
+}
+
+const startKeyListener = () => {
+
+ let keys = {}
+
+ window.addEventListener("keydown", ev => {
+ if(ev.repeat) {
+ return;
+ }
+ if (ev.code == "KeyQ") {
+ if (sidebar.style.display === "none") {
+ sidebar.style.display = ""
+ } else {
+ sidebar.style.display = "none"
+ }
+ }
+ keys[ev.code] = true
+ });
+
+ window.addEventListener("keyup", ev => {
+ if (ev.repeat) {
+ return
+ }
+ keys[ev.code] = false
+ })
+
+ return () => {
+ return keys
+ }
+}
+
+const trackMouseMovement = () => {
+
+ let pos: Vec2 = {x : 0, y: 0}
+
+ window.addEventListener("mousemove", ev => {
+ pos = {x: ev.x, y: ev.y}
+ })
+
+ return () => {
+ return pos
+ }
+}
+
+const getTilePos = (width: number, height: number, mousePos: Vec2): Vec2 => {
+
+ const canvas = document.getElementById("canvas") as HTMLCanvasElement
+
+ const canvasRect = canvas.getBoundingClientRect()
+
+ let posX = mousePos.x - canvasRect.x
+ let posY = mousePos.y - canvasRect.y
+
+ let percentX = posX / canvasRect.width
+ let percentY = posY / canvasRect.height
+
+ return {
+ x: Math.floor(percentX * width),
+ y: Math.floor(percentY * height)
+ }
+
+}
+
+const checkInputs = (pressed: {[key: string]: boolean}): Tile => {
+
+ if (pressed["KeyW"]) {
+ return Tile.WALL
+ } else if (pressed["KeyG"]) {
+ return Tile.GHOST_WALL
+ } else if (pressed["KeyF"]) {
+ return Tile.FOOD
+ } else if (pressed["Digit1"]) {
+ return Tile.PLAYER_SPAWN_1
+ } else if (pressed["Digit2"]) {
+ return Tile.PLAYER_SPAWN_2
+ } else if (pressed["Digit3"]) {
+ return Tile.PLAYER_SPAWN_3
+ } else if (pressed["Digit4"]) {
+ return Tile.PLAYER_SPAWN_4
+ } else if (pressed["KeyT"]) {
+ return Tile.THICC_DOT
+ } else if (pressed["KeyI"]) {
+ return Tile.INITIAL_DOT
+ } else if (pressed["KeyC"]) {
+ return Tile.EMPTY
+ }
+
+ return undefined
+}
+
+const checkBounds = (tilePos: Vec2, width: number, height: number) => {
+ if (tilePos.x < 0 || tilePos.x >= width || tilePos.y < 0 || tilePos.y >= height) return false
+ return true
+}
+
+const runMapEditor = (width: number, height: number) => {
+
+ sidebar.style.display = ""
+
+ let data: number[] = new Array(width * height).fill(0)
+
+ genMap(width, height, data, Tile.EMPTY)
+
+ let state: GameState = {
+ started: true,
+ input: {},
+ players: {},
+ items: {},
+ mapId: 0
+ }
+
+ let frame = 0
+ const updateGraphics = startGraphicsUpdater()
+ const getInput = startKeyListener()
+ const getMousePos = trackMouseMovement()
+
+ const loop = () => {
+
+ const mousePos = getMousePos()
+ const tilePos = getTilePos(width, height, mousePos)
+
+ const pressed = getInput()
+ const tile = checkInputs(pressed)
+
+ if (tile !== undefined && checkBounds(tilePos, width, height)) {
+ let current = data[tilePos.y * width + tilePos.x];
+ if (current != tile) {
+ data[tilePos.y * width + tilePos.x] = tile
+ genMap(width, height, data, 0)
+ }
+ }
+
+ updateGraphics(state, frame, true)
+
+ requestAnimationFrame(loop)
+ }
+
+ requestAnimationFrame(loop)
+
+}
diff --git a/client/src/logic/movement.ts b/client/src/logic/movement.ts
index 40cfc3e..f03008b 100644
--- a/client/src/logic/movement.ts
+++ b/client/src/logic/movement.ts
@@ -1,5 +1,5 @@
import { getMap } from "../map.js"
-import { Vec2, Map, Rotation, Key, Player, GameState } from "../types.js"
+import { Vec2, Map, Rotation, Key, Player, GameState, Tile } from "../types.js"
const MOVE_SPEED = .1
@@ -20,7 +20,7 @@ const getTile = (
): number => {
let x = Math.round(pos.x + ox)
let y = Math.round(pos.y + oy)
- if (x < 0 || x >= map.width || y < 0 || y >= map.height) return 1
+ if (x < 0 || x >= map.width || y < 0 || y >= map.height) return Tile.WALL
return map.data[y * map.width + x]
}
@@ -73,13 +73,11 @@ const incrementPos = (
pos.x -= speed
break
case Rotation.EAST:
- pos.y += speed
+ pos.x += speed
break
}
}
-let i = 0
-
const updateMovementForPlayer = (
map: Map,
player: Player,
@@ -91,7 +89,7 @@ const updateMovementForPlayer = (
let currentPosition = player.pos
let turningFrontTile = getTileFrontWithRot(map, currentPosition, inputRot)
- if (turningFrontTile == 1 || turningFrontTile == 2) {
+ if (turningFrontTile == Tile.WALL || turningFrontTile == Tile.GHOST_WALL) {
inputRot = Rotation.NOTHING
}
@@ -109,7 +107,7 @@ const updateMovementForPlayer = (
incrementPos(movePos, moveRot, MOVE_SPEED)
let frontTile = getTileFrontWithRot(map, currentPosition, moveRot)
- if (frontTile != 1 && frontTile != 2) {
+ if (frontTile != Tile.WALL && frontTile != Tile.GHOST_WALL) {
player.pos = movePos
player.moving = true
} else {
diff --git a/client/src/logic/players.ts b/client/src/logic/players.ts
index ebe469f..96779fe 100644
--- a/client/src/logic/players.ts
+++ b/client/src/logic/players.ts
@@ -33,7 +33,7 @@ export const updatePlayers = (data: GameState, input: Input) => {
data.players[added] ||= {
pos: {x: 1, y: 1},
inputRotation: Rotation.EAST,
- moveRotation: Rotation.EAST,
+ moveRotation: Rotation.NOTHING,
moving: false,
};
diff --git a/client/src/main.ts b/client/src/main.ts
index a6cc3ba..c8a1758 100644
--- a/client/src/main.ts
+++ b/client/src/main.ts
@@ -9,9 +9,9 @@ lobby.style.display = "none"
join.onsubmit = async function(event) {
event.preventDefault()
-
- const room_code = this.elements.room_code.value.trim()
- const player_name = this.elements.name.value.trim()
+
+ const room_code = (document.getElementById("room_code")).value
+ const player_name = (document.getElementById("player_name")).value
if (room_code == '') {
alert('Please enter a room code')
diff --git a/client/src/map.ts b/client/src/map.ts
index e6fab9d..d26c467 100644
--- a/client/src/map.ts
+++ b/client/src/map.ts
@@ -126,6 +126,24 @@ export const genItems = (map: Map): Items => {
let mapData: Maps = {}
let id: number = 0
+export const genMap = (
+ width: number,
+ height: number,
+ data: number[],
+ mapId: number,
+): Map => {
+
+ mapData[mapId] = {
+ data: structuredClone(data),
+ walls: genWalls(width, height, data),
+ width,
+ height,
+ id: mapId
+ }
+
+ return mapData[mapId]
+}
+
export const loadMap = (
width: number,
height: number,
diff --git a/client/src/net/game.ts b/client/src/net/game.ts
index c8e5991..88a36b1 100644
--- a/client/src/net/game.ts
+++ b/client/src/net/game.ts
@@ -52,7 +52,6 @@ export class Game {
* If the frame is ahead of the current latest frame, the game will be run until that frame.
*/
setInput(frame: number, input: Input) {
- console.log('input', frame, input)
this.editFrame(frame, (index: number): void => {
let past = this.history[index - 1];
if(index === 0) {
@@ -66,7 +65,6 @@ export class Game {
}
setData(frame: number, data: GameState) {
- console.log('data', frame, data)
this.editFrame(frame, (index: number): void => {
this.history[index] = {
data,
diff --git a/client/src/net/multiplayer.ts b/client/src/net/multiplayer.ts
index e9f3057..5dcf86d 100644
--- a/client/src/net/multiplayer.ts
+++ b/client/src/net/multiplayer.ts
@@ -80,7 +80,7 @@ export function multiplayer(
function update(input: PlayerInput, frame: number) {
if(input === undefined) { // used to update the game locally
if(hasState) {
- applyInput({})
+ applyInput({frame})
}
return;
}
diff --git a/client/src/renderer.ts b/client/src/renderer.ts
index c7bbbc2..8482ca6 100644
--- a/client/src/renderer.ts
+++ b/client/src/renderer.ts
@@ -1,7 +1,5 @@
import { getMap } from "./map.js";
-import { Items, Players, Rotation, ItemType, Map, Wall, GameState } from "./types.js";
-
-const ATLAS_TILE_WIDTH = 32
+import { Items, Players, Rotation, ItemType, Map, Wall, GameState, Tile, ATLAS_TILE_WIDTH } from "./types.js";
const update_style = (width: number, height: number) => {
@@ -257,20 +255,82 @@ const draw_map_canvas = (
}
+const draw_debug_sprites = (
+ ctx: CanvasRenderingContext2D,
+ atlas: CanvasImageSource,
+ map: Map
+) => {
+
+ for (let y = 0; y < map.height; y++) {
+ for (let x = 0; x < map.width; x++) {
+
+ let tile_type = map.data[y * map.width + x]
+
+
+ let atlas_index: [number, number];
+ switch (tile_type) {
+ case Tile.EMPTY:
+ case Tile.WALL:
+ continue
+ case Tile.GHOST_WALL:
+ atlas_index = [4, 0]
+ break
+ case Tile.FOOD:
+ atlas_index = [3, 0]
+ break
+ case Tile.PLAYER_SPAWN_1:
+ atlas_index = [3, 1]
+ break
+ case Tile.PLAYER_SPAWN_2:
+ atlas_index = [4, 1]
+ break
+ case Tile.PLAYER_SPAWN_3:
+ atlas_index = [3, 2]
+ break
+ case Tile.PLAYER_SPAWN_4:
+ atlas_index = [4, 2]
+ break
+ case Tile.THICC_DOT:
+ atlas_index = [4, 3]
+ break
+ case Tile.INITIAL_DOT:
+ atlas_index = [3, 3]
+ break
+ }
+
+ draw_sprite (
+ ctx,
+ x,
+ y,
+ 1,
+ atlas,
+ atlas_index,
+ ATLAS_TILE_WIDTH,
+ 0
+ )
+
+ }
+ }
+}
+
let map_canvas = document.createElement("canvas")
const draw_map = (
ctx: CanvasRenderingContext2D,
atlas: CanvasImageSource,
map: Map,
- last: number | undefined
+ last: number | undefined,
+ editor: boolean
) => {
- if (map.id !== last) {
+ if (map.id !== last || editor) {
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)
+ if (editor) {
+ draw_debug_sprites(map_ctx, atlas, map)
+ }
}
ctx.drawImage (
@@ -292,7 +352,8 @@ export const startGraphicsUpdater = () => {
*/
return (
data: GameState,
- frame: number
+ frame: number,
+ editor: boolean = false
) => {
let map = getMap(data.mapId)
@@ -308,7 +369,7 @@ export const startGraphicsUpdater = () => {
let ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height)
- draw_map(ctx, atlas, map, last_map_drawn)
+ draw_map(ctx, atlas, map, last_map_drawn, editor)
draw_items(ctx, atlas, data.items)
draw_players(ctx, atlas, data.players, frame)
update_style(map.width, map.height)
diff --git a/client/src/types.ts b/client/src/types.ts
index df0c8b1..02d5adb 100644
--- a/client/src/types.ts
+++ b/client/src/types.ts
@@ -1,4 +1,20 @@
+export const ATLAS_TILE_WIDTH = 32
+
+export enum Tile {
+ EMPTY,
+ WALL,
+ GHOST_WALL,
+ FOOD,
+ PLAYER_SPAWN_1,
+ PLAYER_SPAWN_2,
+ PLAYER_SPAWN_3,
+ PLAYER_SPAWN_4,
+ GHOST_SPAWN,
+ THICC_DOT,
+ INITIAL_DOT
+}
+
export enum Wall {
EMPTY,
WALL_HZ,
@@ -63,8 +79,8 @@ export type Player = {
pos: Vec2,
moveRotation: Rotation,
inputRotation: Rotation,
- name?: string,
- moving: boolean
+ moving: boolean,
+ name?: string
}
export type PlayerInput = {