import { getMap } from "../map.js" import { Vec2, Map, Rotation, Key, Player, GameState, Tile, BoundingBox } from "../types.js" export const MOVE_SPEED = .08333 export const roundPos = (pos: Vec2): Vec2 => { return {x: Math.round(pos.x), y: Math.round(pos.y)} } export const isStablePos = (pos: Vec2): boolean => { let rpos = roundPos(pos) return Math.abs(rpos.x - pos.x) < .05 && Math.abs(rpos.y - pos.y) < .05 } export const getTile = ( map: Map, pos: Vec2, ox: number, oy: number ): number => { let x = Math.round(pos.x + ox) let y = Math.round(pos.y + oy) x = (x + map.width) % map.width y = (y + map.height) % map.height return map.data[y * map.width + x] } export const wrapPos = (pos: Vec2, map: Map) => { pos.x = (pos.x + map.width) % map.width pos.y = (pos.y + map.height) % map.height } export const getTileFrontWithRot = ( map: Map, pos: Vec2, rot: Rotation ): number => { let collider = 1 switch(rot) { case Rotation.NORTH: collider = getTile(map, pos, 0, -.51) break case Rotation.SOUTH: collider = getTile(map, pos, 0, .51) break case Rotation.WEST: collider = getTile(map, pos, -.51, 0) break case Rotation.EAST: collider = getTile(map, pos, .51, 0) break } return collider } const getRot = (key: Key): Rotation => { switch (key) { case Key.UP: return Rotation.NORTH case Key.DOWN: return Rotation.SOUTH case Key.LEFT: return Rotation.WEST case Key.RIGHT: return Rotation.EAST case Key.NOTHING: return Rotation.NOTHING } } export const incrementPos = ( pos: Vec2, rot: Rotation, speed: number ): void => { switch (rot) { case Rotation.NORTH: pos.y -= speed break case Rotation.SOUTH: pos.y += speed break case Rotation.WEST: pos.x -= speed break case Rotation.EAST: pos.x += speed break } } const updateMovementForPlayer = ( map: Map, player: Player, inputKey: Key ) => { let inputRot = getRot(inputKey) let moveRot = player.moveRotation let speed = MOVE_SPEED let currentPosition = player.pos let turningFrontTile = getTileFrontWithRot(map, currentPosition, inputRot) if (turningFrontTile == Tile.WALL || turningFrontTile == Tile.GHOST_WALL || turningFrontTile == Tile.GHOST_EXIT) { inputRot = Rotation.NOTHING } let turning = inputRot != Rotation.NOTHING && inputRot != moveRot player.inputRotation = inputRot if (player.velocityRotation != Rotation.NOTHING) { moveRot = player.velocityRotation speed *= 1.5 } else if (turning && isStablePos(currentPosition)) { currentPosition = roundPos(currentPosition) player.moveRotation = inputRot moveRot = inputRot } let movePos = structuredClone(currentPosition) incrementPos(movePos, moveRot, speed) wrapPos(movePos, map) let frontTile = getTileFrontWithRot(map, currentPosition, moveRot) if (frontTile != Tile.WALL && frontTile != Tile.GHOST_WALL && frontTile != Tile.GHOST_EXIT) { player.pos = movePos player.moving = true } else { player.pos = roundPos(currentPosition) player.moving = false player.velocityRotation = Rotation.NOTHING } } const createBoundingBox = (player: Player): BoundingBox => { let pos = player.pos let width = player.thiccLeft > 0 ? 2 : 1 return { x: pos.x - width/2, y: pos.y - width/2, w: width, h: width } } const checkBoundingBox = (aBB: BoundingBox, bBB: BoundingBox): Rotation => { if ( aBB.x < bBB.x + bBB.w && aBB.x + aBB.w > bBB.x && aBB.y < bBB.y + bBB.h && aBB.y + aBB.h > bBB.y ) { let diff = {x: aBB.x - bBB.x, y: aBB.y - bBB.y} if (Math.abs(diff.x) > Math.abs(diff.y)) { if (diff.x > 0) { return Rotation.EAST } else { return Rotation.WEST } } else { if (diff.y < 0) { return Rotation.NORTH } else { return Rotation.SOUTH } } } else { return Rotation.NOTHING } } const flipRotation = (rot: Rotation): Rotation => { switch (rot) { case Rotation.NOTHING: return Rotation.NOTHING case Rotation.NORTH: return Rotation.SOUTH case Rotation.SOUTH: return Rotation.NORTH case Rotation.EAST: return Rotation.WEST case Rotation.WEST: return Rotation.EAST } } const updateCollision = (data: GameState) => { let players: Player[] = Object.values(data.players).filter(p => p != null && p !== undefined) let bb = structuredClone(players).map(p => createBoundingBox(p)) let num = players.length for (let i = 0; i < num - 1; i++) { for (let j = i + 1; j < num; j++) { if (players[i].dead || players[j].dead) { continue } let rot = checkBoundingBox(bb[i], bb[j]) if (rot == Rotation.NOTHING) { continue } if (players[i].thiccLeft > 0 && players[j].thiccLeft == 0) { players[j].dead = true players[i].framesDead = 0 } else if (players[j].thiccLeft > 0 && players[i].thiccLeft == 0) { players[i].dead = true players[i].framesDead = 0 } else { players[i].velocityRotation = rot players[j].velocityRotation = flipRotation(rot) } } } } export const updateMovement = (data: GameState) => { let map = getMap(data.mapId) if (!map) return updateCollision(data) for (const id in data.players) { const player = data.players[id] if (!player || player.dead) { continue } if (player.thiccLeft > 0) { player.thiccLeft-- } if(!player) { continue } let inputKey = data.input[id] updateMovementForPlayer(map, player, inputKey) } }