Initial commit: Tetris Battle Royale multiplayer game
Features: - 2-8 player multiplayer via Socket.io WebSocket - Real-time board synchronization - all players see all boards - Battle royale mechanic: clearing rows sends garbage to opponents - Classic Tetris gameplay with all 7 tetrominoes - Retro visual styling with CRT scanlines and pixel font - Automatic level progression and speed increase - Player elimination and winner announcement Files: - server/index.js: Node.js + Socket.io game server - public/js/: Frontend game logic, rendering, network, and UI - public/css/style.css: Retro Tetris styling - README.md: Setup and usage instructions - PLAN.md: Implementation plan with all phases completed
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
// Network module - Socket.io client handling
|
||||
|
||||
class NetworkManager {
|
||||
constructor() {
|
||||
this.socket = null;
|
||||
this.currentRoom = null;
|
||||
this.currentPlayerId = null;
|
||||
this.players = {};
|
||||
this.gameState = {};
|
||||
this.listeners = {
|
||||
onPlayerJoined: null,
|
||||
onPlayerLeft: null,
|
||||
onGameStarted: null,
|
||||
onStateUpdate: null,
|
||||
onGameOver: null
|
||||
};
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.socket = io();
|
||||
|
||||
this.socket.on('connect', () => {
|
||||
console.log('Connected to server');
|
||||
this.currentPlayerId = this.socket.id;
|
||||
});
|
||||
|
||||
this.socket.on('disconnect', () => {
|
||||
console.log('Disconnected from server');
|
||||
this.currentRoom = null;
|
||||
});
|
||||
|
||||
this.socket.on('player-joined', ({ player, players }) => {
|
||||
this.updatePlayers(players);
|
||||
if (this.listeners.onPlayerJoined) {
|
||||
this.listeners.onPlayerJoined(player);
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on('player-left', ({ playerId, players }) => {
|
||||
delete this.players[playerId];
|
||||
this.updatePlayers(players);
|
||||
if (this.listeners.onPlayerLeft) {
|
||||
this.listeners.onPlayerLeft(playerId);
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on('game-started', ({ players, states }) => {
|
||||
this.updatePlayers(players);
|
||||
this.updateStates(states);
|
||||
if (this.listeners.onGameStarted) {
|
||||
this.listeners.onGameStarted(players, states);
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on('state-update', (states) => {
|
||||
this.updateStates(states);
|
||||
if (this.listeners.onStateUpdate) {
|
||||
this.listeners.onStateUpdate(states);
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on('game-over', (data) => {
|
||||
if (this.listeners.onGameOver) {
|
||||
this.listeners.onGameOver(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
joinRoom(roomName, playerName) {
|
||||
if (!this.socket) return;
|
||||
|
||||
this.currentRoom = roomName;
|
||||
this.socket.emit('join-room', { roomName, playerName });
|
||||
}
|
||||
|
||||
leaveRoom() {
|
||||
if (!this.socket) return;
|
||||
|
||||
if (this.currentRoom) {
|
||||
this.socket.leave(this.currentRoom);
|
||||
}
|
||||
this.currentRoom = null;
|
||||
}
|
||||
|
||||
ready() {
|
||||
if (!this.socket) return;
|
||||
this.socket.emit('ready');
|
||||
}
|
||||
|
||||
sendMove(direction) {
|
||||
if (!this.socket || !this.currentPlayerId) return;
|
||||
this.socket.emit('player-move', { playerId: this.currentPlayerId, direction });
|
||||
}
|
||||
|
||||
sendRotate() {
|
||||
if (!this.socket || !this.currentPlayerId) return;
|
||||
this.socket.emit('player-rotate', { playerId: this.currentPlayerId });
|
||||
}
|
||||
|
||||
sendDrop() {
|
||||
if (!this.socket || !this.currentPlayerId) return;
|
||||
this.socket.emit('player-drop', { playerId: this.currentPlayerId, hard: false });
|
||||
}
|
||||
|
||||
sendHardDrop() {
|
||||
if (!this.socket || !this.currentPlayerId) return;
|
||||
this.socket.emit('player-drop', { playerId: this.currentPlayerId, hard: true });
|
||||
}
|
||||
|
||||
updatePlayers(players) {
|
||||
this.players = {};
|
||||
players.forEach(p => {
|
||||
this.players[p.id] = p;
|
||||
});
|
||||
}
|
||||
|
||||
updateStates(states) {
|
||||
states.forEach(s => {
|
||||
this.gameState[s.playerId] = s;
|
||||
});
|
||||
}
|
||||
|
||||
getPlayer(playerId) {
|
||||
return this.players[playerId];
|
||||
}
|
||||
|
||||
getGameState(playerId) {
|
||||
return this.gameState[playerId];
|
||||
}
|
||||
|
||||
getAllPlayers() {
|
||||
return this.players;
|
||||
}
|
||||
|
||||
getAllGameStates() {
|
||||
return this.gameState;
|
||||
}
|
||||
|
||||
setListener(event, callback) {
|
||||
const listenerMap = {
|
||||
'player-joined': 'onPlayerJoined',
|
||||
'player-left': 'onPlayerLeft',
|
||||
'game-started': 'onGameStarted',
|
||||
'state-update': 'onStateUpdate',
|
||||
'game-over': 'onGameOver'
|
||||
};
|
||||
if (callback) {
|
||||
this.listeners[listenerMap[event]] = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const network = new NetworkManager();
|
||||
Reference in New Issue
Block a user