e7917a338e
Changes: - Removed room-based architecture, now using single global lobby - Players only need to enter their name to join - Game starts when all players in lobby are ready (min 2, max 8) - Simplified UI - no room name field, shows "Global Lobby" header - Updated all server events to use io.emit instead of io.to(roomName) Files modified: - server/index.js: Replaced rooms Map with single lobby object - public/index.html: Removed room name input, updated button text - public/js/network.js: Renamed joinRoom/leaveRoom to joinLobby/leaveLobby - public/js/ui.js: Simplified join flow, removed room name validation - public/js/app.js: Updated game header to show "GLOBAL LOBBY" - PLAN.md: Marked all phases as complete
132 lines
3.8 KiB
JavaScript
132 lines
3.8 KiB
JavaScript
// UI Module - Handle screens and user interactions
|
|
|
|
class UIManager {
|
|
constructor() {
|
|
this.screens = {
|
|
room: document.getElementById('room-screen'),
|
|
lobby: document.getElementById('lobby-screen'),
|
|
game: document.getElementById('game-screen'),
|
|
gameover: document.getElementById('gameover-screen')
|
|
};
|
|
|
|
this.inputs = {
|
|
playerName: document.getElementById('player-name')
|
|
};
|
|
|
|
this.buttons = {
|
|
join: document.getElementById('join-btn'),
|
|
ready: document.getElementById('ready-btn'),
|
|
leave: document.getElementById('leave-btn'),
|
|
backToLobby: document.getElementById('back-to-lobby')
|
|
};
|
|
|
|
this.displays = {
|
|
gameRoomName: document.getElementById('game-room-name'),
|
|
playerList: document.getElementById('player-list'),
|
|
battleGrid: document.getElementById('battle-grid'),
|
|
gameStatus: document.getElementById('game-status'),
|
|
winnerDisplay: document.getElementById('winner-display'),
|
|
finalScores: document.getElementById('final-scores')
|
|
};
|
|
|
|
this.bindEvents();
|
|
}
|
|
|
|
bindEvents() {
|
|
this.buttons.join.addEventListener('click', () => this.handleJoin());
|
|
this.buttons.ready.addEventListener('click', () => this.handleReady());
|
|
this.buttons.leave.addEventListener('click', () => this.handleLeave());
|
|
this.buttons.backToLobby.addEventListener('click', () => this.handleBackToLobby());
|
|
|
|
// Allow Enter key to submit forms
|
|
this.inputs.playerName.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') this.handleJoin();
|
|
});
|
|
}
|
|
|
|
showScreen(screenName) {
|
|
Object.values(this.screens).forEach(screen => screen.classList.remove('active'));
|
|
this.screens[screenName].classList.add('active');
|
|
}
|
|
|
|
handleJoin() {
|
|
const playerName = this.inputs.playerName.value.trim();
|
|
|
|
if (!playerName) {
|
|
this.showMessage('Please enter your name');
|
|
return;
|
|
}
|
|
|
|
// Set listener for player joined event
|
|
network.setListener('player-joined', () => {
|
|
this.showScreen('lobby');
|
|
});
|
|
|
|
network.joinLobby(playerName);
|
|
}
|
|
|
|
handleReady() {
|
|
network.ready();
|
|
this.buttons.ready.textContent = 'READY!';
|
|
this.buttons.ready.disabled = true;
|
|
}
|
|
|
|
handleLeave() {
|
|
network.leaveLobby();
|
|
this.showScreen('room');
|
|
}
|
|
|
|
handleBackToLobby() {
|
|
this.showScreen('room');
|
|
}
|
|
|
|
updatePlayerList(players) {
|
|
this.displays.playerList.innerHTML = '';
|
|
Object.values(players).forEach(player => {
|
|
const item = document.createElement('div');
|
|
item.className = 'player-item';
|
|
const statusClass = player.ready ? 'ready' : '';
|
|
item.innerHTML = `
|
|
<span class="name">${this.escapeHtml(player.name)}</span>
|
|
<span class="status ${statusClass}">${player.ready ? 'READY' : 'WAITING'}</span>
|
|
`;
|
|
this.displays.playerList.appendChild(item);
|
|
});
|
|
}
|
|
|
|
showMessage(message) {
|
|
this.displays.gameStatus.textContent = message;
|
|
setTimeout(() => {
|
|
this.displays.gameStatus.textContent = '';
|
|
}, 3000);
|
|
}
|
|
|
|
escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
showGameOver(winner, scores) {
|
|
this.displays.winnerDisplay.textContent = winner
|
|
? `Winner: ${winner}!`
|
|
: 'Game Over!';
|
|
this.displays.winnerDisplay.style.color = winner ? '#0f0' : '#fff';
|
|
|
|
this.displays.finalScores.innerHTML = '';
|
|
Object.entries(scores).forEach(([name, score], index) => {
|
|
const item = document.createElement('div');
|
|
item.className = 'score-item' + (index === 0 ? ' winner' : '');
|
|
item.innerHTML = `
|
|
<span>${this.escapeHtml(name)}</span>
|
|
<span>${score}</span>
|
|
`;
|
|
this.displays.finalScores.appendChild(item);
|
|
});
|
|
|
|
this.showScreen('gameover');
|
|
}
|
|
}
|
|
|
|
window.ui = new UIManager();
|