barkour/MAP.md
w1n5t0n f57c1f16f8 feat: top-down 'Dogpit' arena mode (dota-like view)
Second game mode selectable at dog select (host-authoritative online):
- js/sim_arena.js: top-down sim, same export surface as sim.js — x/y plane
  plus a z hop axis (Space / comma); KOs by knocking dogs into abyss pits
- js/mapgen_arena.js: mirrored symmetric arenas — walls, pits, center
  clearing, guaranteed spawn-to-center corridors, crystals/spikes/launch
  pads, mirrored saw pairs; fallback pit pair since pits are the only KO
  mechanic
- specials re-imagined per dog: zoom dash, ram + hop-slam, zip-leash
  slingshot, blink, hover (floats over pits/saws/spikes)
- render: arena tiles with wall shadows + void pits, top-down dog drawing
  with z-lift over a ground shadow; new fall event/sfx
- B.HOP input bit so 'up' can mean north in top-down (Space also jumps in
  side view); mode toggle UI + mode carried in start/rematch net messages

Tested: arena mapgen determinism/symmetry/connectivity + chaotic matches +
pit/hop scenarios headless; local chaos + full P2P arena match (host mode
flip syncs to client) in two headless browsers with zero page errors.
2026-06-10 15:23:22 +02:00

3.6 KiB
Raw Permalink Blame History

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), then js/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 enum T, input bitmask B, item ids, physics constants, snapshot rate.
  • js/rng.js — seeded mulberry32 (makeRng); randomSeed() is UI-side only.
  • js/mapgen.js — side-view 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/mapgen_arena.js — top-down generateArena(seed): mirrored (left↔right) walls/pits, corner spawns, guaranteed corridors spawn→center, fallback pit pair (pits are the only KO mechanic), mirrored saw pairs.
  • js/physics.js — center-based AABB vs tile grid: moveEntity (per-axis, one-way platform aware), raycast, boxFree, standingOnPlat.
  • js/characters.jsCHARS data (stats + visual params) and updateCharacter(): per-dog special movement (air dash / charge+pound / grapple constraint / blink / jetpack).
  • js/sim.jsauthoritative, DOM-free side-view sim: createGame, step(game, inputs) (60 Hz), combat (hurt: damage% → knockback), mining/items/hazards/KO/respawn/match-end, snapshot/applySnapshot for netplay. Sets game.kind='side'.
  • js/sim_arena.js — top-down "Dogpit" sim, same export surface as sim.js (main.js swaps modules per match). x/y plane + z hop axis; KOs via pit falls; specials re-imagined per dog (dash cooldown, ram/slam, zip-leash, blink, hover). Sets game.kind='arena'.
  • 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); broker network errors 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. Branches on game.kind: side view (drawTiles/drawDog) vs top-down (drawTilesArena/drawDogTop, z-height lifts the dog off its shadow).
  • js/audio.js — WebAudio-synthesized sfx; playEvents maps sim events → sounds.
  • js/main.js — app state machine: screens, char select (incl. mode toggle: gameMode 'side'|'arena', host-authoritative over the wire via mode/start/rematch messages), three match drivers (local / host / client) sharing one rAF fixed-timestep loop; matchSim points at the active sim module.
  • test/smoke.mjsnpm 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 applySnapshot state; anything render reads must survive the snapshot round-trip (player st is re-shaped there).
  • Sim events are the only side-channel: fx, audio, and client tile mutations (tile/crack events) ride on them. Host accumulates pendingEvs between snapshots.
  • All sim/mapgen randomness must use the seeded RNG — never Math.random() inside js/sim.js/js/mapgen.js/js/characters.js paths.
  • 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.