From 113c6d105a0b06603388e5e0ded90ed169ae0c50 Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Sat, 17 Jun 2023 01:18:16 -0400 Subject: [PATCH] map editor --- client/css/editor.css | 21 +++++ client/css/main.css | 5 + client/img/atlas.png | Bin 6304 -> 8168 bytes client/index.html | 2 +- client/js/main.js | 4 +- client/mapeditor.html | 35 +++++++ client/src/editor.ts | 166 ++++++++++++++++++++++++++++++++++ client/src/logic/movement.ts | 12 +-- client/src/logic/players.ts | 2 +- client/src/main.ts | 6 +- client/src/map.ts | 18 ++++ client/src/net/game.ts | 2 - client/src/net/multiplayer.ts | 2 +- client/src/renderer.ts | 75 +++++++++++++-- client/src/types.ts | 20 +++- 15 files changed, 344 insertions(+), 26 deletions(-) create mode 100644 client/css/editor.css create mode 100644 client/mapeditor.html create mode 100644 client/src/editor.ts diff --git a/client/css/editor.css b/client/css/editor.css new file mode 100644 index 0000000..cc3bb88 --- /dev/null +++ b/client/css/editor.css @@ -0,0 +1,21 @@ +canvas { + box-shadow: inset 0 0 1px red; +} + +#sidebar { + background-color: #191919; + position: absolute; + display: flex; + flex-direction: column; + border: 1px solid; + padding: 1rem; +} + +#mapgen { + display: flex; + flex-direction: column; +} + +#export { + margin-top: 1rem; +} diff --git a/client/css/main.css b/client/css/main.css index 87c145c..f8309de 100644 --- a/client/css/main.css +++ b/client/css/main.css @@ -70,4 +70,9 @@ input { border: solid 2px #fff; padding: .25rem; margin-bottom: .215rem; + box-sizing:content-box; +} + +p { + padding: .25rem; } diff --git a/client/img/atlas.png b/client/img/atlas.png index 240705b2c7b8c382bfddfbadf65204d82c0bec03..cb9e802a5056f67bb1097f06d37c43458f113793 100644 GIT binary patch delta 3891 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 rmL`T2g2lNV85c{4DfS1%C{O
- +
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 = {