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.
83 lines
3.2 KiB
HTML
83 lines
3.2 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>BARKOUR — dogfights × parkour</title>
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><text y='13' font-size='13'>🐕</text></svg>">
|
||
<link rel="stylesheet" href="style.css">
|
||
<!-- PeerJS: signaling broker only; game traffic is pure P2P WebRTC.
|
||
If offline, local 2-player still works. -->
|
||
<script src="https://unpkg.com/peerjs@1.5.4/dist/peerjs.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div id="wrap">
|
||
<canvas id="cv" width="960" height="540"></canvas>
|
||
|
||
<div id="ui">
|
||
<div id="mute" title="M to mute">🔊</div>
|
||
<div id="pause-tag" class="hidden">⏸ PAUSED — Esc to resume</div>
|
||
<div id="room-key-tag" class="hidden">room <b id="room-key"></b></div>
|
||
|
||
<!-- main menu -->
|
||
<div id="s-menu" class="screen">
|
||
<h1>BARK<span>OUR</span></h1>
|
||
<p class="tagline">dogfights × parkour</p>
|
||
<button id="btn-local">🛋️ Local — 2 players, 1 keyboard</button>
|
||
<button id="btn-host">📡 Host online room</button>
|
||
<button id="btn-join">🔑 Join with room key</button>
|
||
<p id="menu-status" class="status"></p>
|
||
<div class="help">
|
||
<div><b>P1</b> WASD move · <b>F</b> bite · <b>G</b> special · <b>H</b> item</div>
|
||
<div><b>P2</b> arrows move · <b>K</b> bite · <b>L</b> special · <b>;</b> item</div>
|
||
<div>↓ drops through platforms · bite crystals to mine powerups · last dog standing wins</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- hosting -->
|
||
<div id="s-host" class="screen hidden">
|
||
<h2>Hosting room</h2>
|
||
<div class="bigkey" id="host-key">·····</div>
|
||
<p class="status" id="host-status"></p>
|
||
<p class="hint">Send this key to your opponent. They pick “Join with room key”.</p>
|
||
<button id="btn-host-cancel" class="ghost">Cancel</button>
|
||
</div>
|
||
|
||
<!-- joining -->
|
||
<div id="s-join" class="screen hidden">
|
||
<h2>Join a room</h2>
|
||
<input id="join-key" maxlength="6" placeholder="ROOM KEY" autocomplete="off">
|
||
<button id="btn-join-go">Connect</button>
|
||
<p class="status" id="join-status"></p>
|
||
<button id="btn-join-cancel" class="ghost">Back</button>
|
||
</div>
|
||
|
||
<!-- character select -->
|
||
<div id="s-chars" class="screen wide hidden">
|
||
<h2>Choose your dog</h2>
|
||
<div id="char-grid"></div>
|
||
<p id="chars-status" class="status"></p>
|
||
<div class="row">
|
||
<button id="btn-start" disabled>Start match!</button>
|
||
<button id="btn-chars-back" class="ghost">Back</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- in-game (canvas only; HUD is drawn) -->
|
||
<div id="s-game" class="screen passthrough hidden"></div>
|
||
|
||
<!-- results -->
|
||
<div id="s-result" class="screen hidden">
|
||
<h2 id="result-title">Someone wins!</h2>
|
||
<div class="row">
|
||
<button id="btn-rematch">Rematch (Enter)</button>
|
||
<button id="btn-newdogs">Change dogs</button>
|
||
<button id="btn-result-menu" class="ghost">Menu</button>
|
||
</div>
|
||
<p id="result-wait" class="status hidden">Waiting for the host…</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script type="module" src="js/main.js"></script>
|
||
</body>
|
||
</html>
|