Add spectator mode for late-joining players
- Server: Late joiners are added as spectators instead of players - Server: Send forced-spectator event only to joining spectator (not broadcast) - Server: Track spectators separately and move them to players after game ends - Client: Handle forced-spectator event to show all player boards - Client: Spectators see all boards equally without main/spectator highlighting - Client: Mobile view shows scrollable vertical list of all boards for spectators - Fix: All cleared lines are sent as garbage to each opponent (not randomized) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+43
-2
@@ -83,10 +83,45 @@ function setupNetworkListeners() {
|
||||
network.setListener('game-over', (data) => {
|
||||
endGame(data.states);
|
||||
});
|
||||
|
||||
// Forced spectator - game already in progress
|
||||
network.setListener('forced-spectator', ({ states, players }) => {
|
||||
ui.showScreen('game');
|
||||
ui.showSpectatorMode();
|
||||
|
||||
// Clear old boards
|
||||
renderer.clearAll();
|
||||
|
||||
// Create boards for all players (spectator can see everyone)
|
||||
states.forEach((state) => {
|
||||
const player = network.getPlayer(state.playerId);
|
||||
renderer.createPlayerBoard(state.playerId, player.name);
|
||||
});
|
||||
|
||||
// Set up battle grid layout
|
||||
updateBattleGridLayout(players.length);
|
||||
|
||||
// Start game loop for viewing
|
||||
lastTime = performance.now();
|
||||
requestAnimationFrame(gameLoop);
|
||||
});
|
||||
|
||||
// Spectator joined
|
||||
network.setListener('spectator-joined', (spectator) => {
|
||||
ui.updateSpectatorList(network.getAllSpectators());
|
||||
});
|
||||
|
||||
// Spectator left
|
||||
network.setListener('spectator-left', (spectatorId) => {
|
||||
ui.updateSpectatorList(network.getAllSpectators());
|
||||
});
|
||||
}
|
||||
|
||||
function setupKeyboardControls() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
// Spectators cannot control the game
|
||||
if (network.isSpectator) return;
|
||||
|
||||
if (ui.screens.game.classList.contains('active') && localGame) {
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft':
|
||||
@@ -129,6 +164,8 @@ function setupKeyboardControls() {
|
||||
const handleTouch = (e, action) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// Spectators cannot control the game
|
||||
if (network.isSpectator) return;
|
||||
if (ui.screens.game.classList.contains('active')) {
|
||||
action();
|
||||
}
|
||||
@@ -185,6 +222,10 @@ function endGame(states) {
|
||||
}
|
||||
});
|
||||
|
||||
// Reset spectator mode for next round
|
||||
network.isSpectator = false;
|
||||
ui.hideSpectatorMode();
|
||||
|
||||
ui.showGameOver(winner, scores);
|
||||
}
|
||||
|
||||
@@ -207,8 +248,8 @@ function gameLoop(currentTime) {
|
||||
renderer.renderPlayer(state.playerId, state);
|
||||
});
|
||||
|
||||
// Set active player highlight
|
||||
renderer.setActivePlayer(network.currentPlayerId);
|
||||
// Set active player highlight (or null for spectators to show all boards equally)
|
||||
renderer.setActivePlayer(network.isSpectator ? null : network.currentPlayerId);
|
||||
|
||||
requestAnimationFrame(gameLoop);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user