Files
claudePySnake/web/index.html
Vladyslav Doloman 4dbbf44638 Implement client-side prediction with input broadcasting
Reduces perceived lag over internet by broadcasting player inputs immediately
and predicting next positions on all clients before server update arrives.

Protocol changes:
- Added PLAYER_INPUT message type for broadcasting inputs
- Server broadcasts player inputs to all clients on every MOVE message
- Includes player_id, current direction, and full input_buffer (max 3)

Desktop client (Python):
- Tracks input buffers and predicted head positions for all players
- On PLAYER_INPUT: predicts next head position using buffered input
- On STATE_UPDATE: clears predictions, uses authoritative state
- Renderer draws predicted positions with darker color (60% brightness)

Web client (JavaScript):
- Same prediction logic as desktop client
- Added darkenColor() helper for visual differentiation
- Predicted heads shown at 60% brightness

Benefits:
- Instant visual feedback for own movements (no round-trip wait)
- See other players' inputs before server tick (better collision avoidance)
- Smooth experience bridging input-to-update gap
- Low bandwidth (only direction tuples, not full state)
- Backward compatible (server authoritative, old clients work)

All 39 tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-04 21:21:49 +03:00

74 lines
2.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multiplayer Snake Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>🐍 Multiplayer Snake</h1>
</header>
<div id="connection-panel" class="panel">
<h2>Connect to Server</h2>
<div class="form-group">
<label for="player-name">Your Name:</label>
<input type="text" id="player-name" placeholder="Enter your name" value="Player" maxlength="20">
</div>
<div class="form-group">
<label for="server-url">Server URL:</label>
<input type="text" id="server-url" placeholder="ws://localhost:8889" value="">
</div>
<button id="connect-btn" class="btn btn-primary">Connect</button>
<div id="connection-status" class="status"></div>
</div>
<div id="game-panel" class="panel" style="display: none;">
<div class="game-area">
<canvas id="game-canvas"></canvas>
<div id="game-overlay" class="overlay">
<div class="overlay-content">
<h2>Waiting for game to start...</h2>
<p>Press <kbd>SPACE</kbd> to start the game</p>
<p>Use <kbd></kbd> <kbd></kbd> <kbd></kbd> <kbd></kbd> or <kbd>W</kbd> <kbd>A</kbd> <kbd>S</kbd> <kbd>D</kbd> to move</p>
</div>
</div>
</div>
<aside class="sidebar">
<div class="score-panel">
<h3>Players</h3>
<div id="players-list"></div>
</div>
<div class="controls-panel">
<h3>Controls</h3>
<div class="control-info">
<p><kbd></kbd> <kbd></kbd> <kbd></kbd> <kbd></kbd> Move</p>
<p><kbd>W</kbd> <kbd>A</kbd> <kbd>S</kbd> <kbd>D</kbd> Move</p>
<p><kbd>SPACE</kbd> Start Game</p>
</div>
<button id="disconnect-btn" class="btn btn-secondary">Disconnect</button>
</div>
</aside>
</div>
</div>
<script src="protocol.js"></script>
<script src="game.js"></script>
<script>
// Auto-detect WebSocket URL based on page hostname
const wsUrl = document.getElementById('server-url');
if (window.location.protocol === 'file:') {
wsUrl.value = 'ws://localhost:8889';
} else {
const host = window.location.hostname;
const port = 8889; // Default WebSocket port
wsUrl.value = `ws://${host}:${port}`;
}
</script>
</body>
</html>