Sim: clamp knockback under tile size (wall tunneling), bomb/ball terminal velocity, grapple constraint no longer drags players into terrain, bite window ends on getting hit, shield/boost cleared on death, spawn invuln preserved through countdown, spike/saw events only on real damage. Mapgen: spawn footprint validation (was embedding dogs in 58% of seeds), saw paths rejected if they grind terrain or sweep spawns, towers no longer hang slabs over pits. Net: heartbeat+watchdog for dead peers, broker-error tolerance once P2P link is up, join/host reentrancy guards. UI: text-field keystrokes no longer hit game hotkeys, audio unlocks on mouse, textBaseline leak, snapshot carries onGround/landT so client dogs animate.
2.8 KiB
2.8 KiB
MAP.md — Barkour code index
Vanilla-JS canvas game, no build step. ES modules under js/, served statically.
index.html— DOM shell: all screens (menu/host/join/charselect/game/result) as overlay divs; loads PeerJS from CDN (online play only), thenjs/main.js.style.css— overlay/menu styling; canvas letterboxed to 16:9 via CSS.js/consts.js— grid (TILE=12, 80×45 → 960×540), tile enumT, input bitmaskB, item ids, physics constants, snapshot rate.js/rng.js— seeded mulberry32 (makeRng);randomSeed()is UI-side only.js/mapgen.js—generateMap(seed): ground heightmap, pits, towers, islands, one-way platforms, crystals (hp 3), pads, spikes, rail saws, spawns;PALETTES;sawPos()polyline eval (ping-pong or loop).js/physics.js— center-based AABB vs tile grid:moveEntity(per-axis, one-way platform aware),raycast,boxFree,standingOnPlat.js/characters.js—CHARSdata (stats + visual params) andupdateCharacter(): per-dog special movement (air dash / charge+pound / grapple constraint / blink / jetpack).js/sim.js— authoritative, DOM-free sim:createGame,step(game, inputs)(60 Hz), combat (hurt: damage% → knockback), mining/items/hazards/KO/respawn/match-end,snapshot/applySnapshotfor netplay.js/input.js— keyboard → bitmasks; slot 0 = WASD+FGH, slot 1 = arrows+KL;.js/net.js— PeerJS wrapper:hostRoom/joinRoom; room key = host peer id suffix; signaling via PeerJS cloud, game traffic pure P2P. Runs a 2s heartbeat + 8s watchdog (WebRTC close events are unreliable); brokernetworkerrors are ignored once the data channel is up.js/render.js— canvas: cached seeded background, tiles, procedural dog drawing, particles/ghosts driven by sim events (fxEvents), HUD, banners.js/audio.js— WebAudio-synthesized sfx;playEventsmaps sim events → sounds.js/main.js— app state machine: screens, char select, three match drivers (local / host / client) sharing one rAF fixed-timestep loop.test/smoke.mjs—npm test: headless mapgen determinism + chaotic full matches + targeted mining/stocks scenarios.
Conventions & gotchas
- Client never simulates. In netplay the joiner only sends input bits and renders
applySnapshotstate; anything render reads must survive the snapshot round-trip (playerstis re-shaped there). - Sim events are the only side-channel: fx, audio, and client tile mutations (
tile/crackevents) ride on them. Host accumulatespendingEvsbetween snapshots. - All sim/mapgen randomness must use the seeded RNG — never
Math.random()insidejs/sim.js/js/mapgen.js/js/characters.jspaths. - Velocities must stay < TILE (12 px/tick) or AABB collision tunnels.
- 7 as an arc end-angle in render means "> 2π" (full circle), a deliberate shorthand.