pong-multiplayer / index.html
SignorNessuno's picture
Add 2 files
eec3711 verified
Raw History Blame Contribute Delete
49.6 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Cyber Pong Explosion - Online Multiplayer</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <style> * { margin: 0; padding: 0; box-sizing: border-box; touch-action: manipulation; } body { background-color: #0a0a1a; color: #00fffc; font-family: 'Orbitron', 'Arial', sans-serif; overflow: hidden; height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; -webkit-tap-highlight-color: transparent; } @font-face { font-family: 'Orbitron'; src: url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap'); } .game-container { position: relative; width: 100%; max-width: 800px; height: 100vh; max-height: 500px; border: 3px solid #00fffc; box-shadow: 0 0 20px #00fffc, inset 0 0 20px rgba(0, 255, 252, 0.3); border-radius: 10px; overflow: hidden; background: radial-gradient(circle at center, #0a0a1a 0%, #000 100%); } @media (max-width: 600px) { .game-container { border-radius: 0; border: none; max-height: none; height: 100vh; } } .paddle { position: absolute; width: 15px; height: 100px; background: linear-gradient(to bottom, #00fffc, #0084ff); border-radius: 5px; box-shadow: 0 0 10px #00fffc; } @media (max-width: 600px) { .paddle { width: 12px; height: 80px; } } #playerPaddle { left: 20px; } #aiPaddle, #opponentPaddle { right: 20px; } .ball { position: absolute; width: 20px; height: 20px; background: #ff00e4; border-radius: 50%; box-shadow: 0 0 15px #ff00e4; } @media (max-width: 600px) { .ball { width: 16px; height: 16px; } } .score { position: absolute; top: 20px; font-size: 2rem; font-weight: bold; text-shadow: 0 0 10px #00fffc; } @media (max-width: 600px) { .score { font-size: 1.5rem; top: 10px; } } #playerScore { left: 20%; } #aiScore, #opponentScore { right: 20%; } .center-line { position: absolute; top: 0; left: 50%; width: 2px; height: 100%; background: linear-gradient(to bottom, transparent 0%, rgba(0, 255, 252, 0.3) 10%, transparent 20%, rgba(0, 255, 252, 0.3) 30%, transparent 40%, rgba(0, 255, 252, 0.3) 50%, transparent 60%, rgba(0, 255, 252, 0.3) 70%, transparent 80%, rgba(0, 255, 252, 0.3) 90%, transparent 100%); } .particle { position: absolute; width: 5px; height: 5px; border-radius: 50%; pointer-events: none; } .power-up { position: absolute; width: 20px; height: 20px; border-radius: 50%; box-shadow: 0 0 10px currentColor; animation: pulse 1.5s infinite; } @media (max-width: 600px) { .power-up { width: 16px; height: 16px; } } @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.2); opacity: 0.7; } 100% { transform: scale(1); opacity: 1; } } .power-up.speed { background-color: #ff00e4; color: #ff00e4; } .power-up.size { background-color: #00ff00; color: #00ff00; } .power-up.freeze { background-color: #00b4ff; color: #00b4ff; } .game-over { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 10; display: none; } .game-over h1 { font-size: 2.5rem; margin-bottom: 20px; text-shadow: 0 0 15px #ff00e4; color: #ff00e4; text-align: center; padding: 0 20px; } @media (max-width: 600px) { .game-over h1 { font-size: 2rem; } } .game-over p { font-size: 1.2rem; margin-bottom: 30px; text-align: center; padding: 0 20px; } .btn { padding: 10px 20px; background: linear-gradient(to right, #00fffc, #0084ff); border: none; border-radius: 5px; color: #0a0a1a; font-family: 'Orbitron', sans-serif; font-size: 1rem; cursor: pointer; transition: all 0.3s; box-shadow: 0 0 10px #00fffc; margin: 5px; } @media (max-width: 600px) { .btn { padding: 8px 16px; font-size: 0.9rem; } } .btn:hover { transform: scale(1.05); box-shadow: 0 0 20px #00fffc; } .start-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 10; padding: 20px; } .start-screen h1 { font-size: 2.5rem; margin-bottom: 20px; text-shadow: 0 0 15px #00fffc; color: #00fffc; text-align: center; } @media (max-width: 600px) { .start-screen h1 { font-size: 2rem; } } .start-screen p { font-size: 1rem; margin-bottom: 20px; max-width: 500px; text-align: center; line-height: 1.6; } @media (max-width: 600px) { .start-screen p { font-size: 0.9rem; } } .instructions { margin-top: 20px; font-size: 0.9rem; color: #00b4ff; text-align: center; } @media (max-width: 600px) { .instructions { font-size: 0.8rem; margin-top: 15px; } } .power-up-indicator { position: absolute; bottom: 20px; font-size: 0.8rem; color: #00fffc; text-align: center; width: 100%; display: none; padding: 0 10px; } @media (max-width: 600px) { .power-up-indicator { font-size: 0.7rem; bottom: 15px; } } .glow { animation: glow 1.5s infinite alternate; } @keyframes glow { from { text-shadow: 0 0 5px #00fffc; } to { text-shadow: 0 0 15px #00fffc, 0 0 20px #0084ff; } } .multiplayer-options { display: flex; gap: 15px; margin-top: 20px; flex-wrap: wrap; justify-content: center; } @media (max-width: 600px) { .multiplayer-options { gap: 10px; } } .room-code-container { margin-top: 20px; display: none; flex-direction: column; align-items: center; text-align: center; padding: 0 20px; } .room-code { font-size: 1.2rem; letter-spacing: 3px; margin: 10px 0; padding: 8px 15px; background: rgba(0, 255, 252, 0.1); border: 1px solid #00fffc; border-radius: 5px; } @media (max-width: 600px) { .room-code { font-size: 1rem; letter-spacing: 2px; padding: 6px 12px; } } .waiting-message { margin-top: 15px; color: #00b4ff; font-size: 1rem; } @media (max-width: 600px) { .waiting-message { font-size: 0.9rem; } } .connection-status { position: absolute; top: 10px; right: 10px; font-size: 0.7rem; display: flex; align-items: center; } .connection-status .indicator { width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; } .connection-status .connected { background-color: #00ff00; box-shadow: 0 0 5px #00ff00; } .connection-status .disconnected { background-color: #ff0000; box-shadow: 0 0 5px #ff0000; } .connection-status .connecting { background-color: #ffff00; box-shadow: 0 0 5px #ffff00; animation: pulse 1s infinite; } .player-name { position: absolute; top: 50px; font-size: 0.8rem; } @media (max-width: 600px) { .player-name { top: 40px; font-size: 0.7rem; } } #playerName { left: 20%; } #opponentName { right: 20%; } .touch-controls { position: absolute; bottom: 20px; left: 0; width: 100%; display: flex; justify-content: space-between; padding: 0 30px; z-index: 5; display: none; } @media (max-width: 600px) { .touch-controls { display: flex; } } .touch-btn { width: 70px; height: 70px; background: rgba(0, 255, 252, 0.2); border: 2px solid #00fffc; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #00fffc; font-size: 1.5rem; user-select: none; -webkit-user-select: none; touch-action: manipulation; } @media (max-width: 400px) { .touch-btn { width: 60px; height: 60px; font-size: 1.2rem; } } .orientation-warning { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #0a0a1a; color: #00fffc; display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 100; display: none; text-align: center; padding: 20px; } .orientation-warning i { font-size: 3rem; margin-bottom: 20px; color: #ff00e4; } .orientation-warning h2 { font-size: 1.5rem; margin-bottom: 15px; } .orientation-warning p { font-size: 1rem; max-width: 300px; line-height: 1.5; } </style> </head> <body> <div class="game-container"> <div class="center-line"></div> <div class="paddle" id="playerPaddle"></div> <div class="paddle" id="opponentPaddle" style="display: none;"></div> <div class="paddle" id="aiPaddle"></div> <div class="ball"></div> <div class="score" id="playerScore">0</div> <div class="score" id="opponentScore" style="display: none;">0</div> <div class="score" id="aiScore">0</div> <div class="player-name" id="playerName">YOU</div> <div class="player-name" id="opponentName" style="display: none;">OPPONENT</div> <div class="power-up-indicator" id="powerUpIndicator"></div> <div class="touch-controls" id="touchControls"> <div class="touch-btn" id="upBtn"><i class="fas fa-arrow-up"></i></div> <div class="touch-btn" id="downBtn"><i class="fas fa-arrow-down"></i></div> </div> <div class="game-over"> <h1>GAME OVER</h1> <p id="gameResult"></p> <button class="btn" id="restartBtn">PLAY AGAIN</button> </div> <div class="start-screen"> <h1>CYBER PONG EXPLOSION</h1> <p>Experience the ultimate futuristic pong battle with explosive effects and power-ups!</p> <div class="multiplayer-options"> <button class="btn" id="singlePlayerBtn">SINGLE PLAYER</button> <button class="btn" id="multiplayerBtn">ONLINE MULTIPLAYER</button> </div> <div class="room-code-container" id="roomCodeContainer"> <p>Share this code with your friend:</p> <div class="room-code" id="roomCode"></div> <div class="waiting-message" id="waitingMessage">Waiting for opponent to join...</div> </div> <div class="instructions"> <p><i class="fas fa-arrow-up"></i> <i class="fas fa-arrow-down"></i> Move your paddle with UP/DOWN keys or touch controls</p> <p>Collect power-ups to gain advantages!</p> </div> </div> </div> <div class="orientation-warning" id="orientationWarning"> <i class="fas fa-rotate"></i> <h2>Please rotate your device</h2> <p>For the best gaming experience, please play in landscape mode.</p> </div> <div class="connection-status" id="connectionStatus"> <div class="indicator disconnected"></div> <span>Disconnected</span> </div> <script> document.addEventListener('DOMContentLoaded', () => { // Game elements const gameContainer = document.querySelector('.game-container'); const playerPaddle = document.getElementById('playerPaddle'); const aiPaddle = document.getElementById('aiPaddle'); const opponentPaddle = document.getElementById('opponentPaddle'); const ball = document.querySelector('.ball'); const playerScore = document.getElementById('playerScore'); const aiScore = document.getElementById('aiScore'); const opponentScore = document.getElementById('opponentScore'); const startScreen = document.querySelector('.start-screen'); const gameOverScreen = document.querySelector('.game-over'); const gameResult = document.getElementById('gameResult'); const singlePlayerBtn = document.getElementById('singlePlayerBtn'); const multiplayerBtn = document.getElementById('multiplayerBtn'); const startBtn = document.getElementById('startBtn'); const restartBtn = document.getElementById('restartBtn'); const powerUpIndicator = document.getElementById('powerUpIndicator'); const roomCodeContainer = document.getElementById('roomCodeContainer'); const roomCodeDisplay = document.getElementById('roomCode'); const waitingMessage = document.getElementById('waitingMessage'); const connectionStatus = document.getElementById('connectionStatus'); const playerNameDisplay = document.getElementById('playerName'); const opponentNameDisplay = document.getElementById('opponentName'); const touchControls = document.getElementById('touchControls'); const upBtn = document.getElementById('upBtn'); const downBtn = document.getElementById('downBtn'); const orientationWarning = document.getElementById('orientationWarning'); // Check if mobile device const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); // Game state let gameRunning = false; let isMultiplayer = false; let isHost = false; let roomCode = ''; let playerName = 'Player' + Math.floor(Math.random() * 1000); let opponentName = 'Opponent'; let playerScoreValue = 0; let aiScoreValue = 0; let opponentScoreValue = 0; let gameSpeed = 1; let lastPowerUpTime = 0; let activePowerUp = null; let powerUpEndTime = 0; let touchUpActive = false; let touchDownActive = false; // Ball properties let ballX = 400; let ballY = 250; let ballSpeedX = 3 * gameSpeed; // Velocità iniziale più lenta let ballSpeedY = 3 * gameSpeed; // Velocità iniziale più lenta let ballSize = 20; let speedIncreaseFactor = 1.05; // Fattore di incremento della velocità ad ogni rimbalzo // Paddle properties const paddleHeight = isMobile ? 80 : 100; const paddleWidth = isMobile ? 12 : 15; let playerPaddleY = 200; let aiPaddleY = 200; let opponentPaddleY = 200; const paddleSpeed = 8 * gameSpeed; // Game area dimensions const gameWidth = gameContainer.clientWidth; const gameHeight = gameContainer.clientHeight; // WebSocket connection let socket = null; let reconnectAttempts = 0; const maxReconnectAttempts = 5; // Power-ups const powerUps = [ { type: 'speed', color: '#ff00e4', duration: 5000, effect: () => { gameSpeed = 1.5; } }, { type: 'size', color: '#00ff00', duration: 7000, effect: () => { playerPaddle.style.height = (paddleHeight * 1.5) + 'px'; } }, { type: 'freeze', color: '#00b4ff', duration: 3000, effect: () => { if (isMultiplayer) { opponentPaddle.style.opacity = '0.5'; } else { aiPaddle.style.opacity = '0.5'; } }} ]; // Initialize game init(); function init() { // Set up event listeners singlePlayerBtn.addEventListener('click', () => { isMultiplayer = false; startGame(); }); multiplayerBtn.addEventListener('click', startMultiplayerGame); restartBtn.addEventListener('click', startGame); // Generate a random player name playerName = 'Player' + Math.floor(Math.random() * 1000); playerNameDisplay.textContent = playerName; // Initialize connection status updateConnectionStatus('disconnected'); // Set up touch controls if (isMobile) { touchControls.style.display = 'flex'; upBtn.addEventListener('touchstart', (e) => { e.preventDefault(); touchUpActive = true; }); upBtn.addEventListener('touchend', (e) => { e.preventDefault(); touchUpActive = false; }); downBtn.addEventListener('touchstart', (e) => { e.preventDefault(); touchDownActive = true; }); downBtn.addEventListener('touchend', (e) => { e.preventDefault(); touchDownActive = false; }); // Prevent scrolling when touching game area gameContainer.addEventListener('touchmove', (e) => { e.preventDefault(); }, { passive: false }); } // Check orientation on mobile if (isMobile) { checkOrientation(); window.addEventListener('resize', checkOrientation); window.addEventListener('orientationchange', checkOrientation); } } // Check device orientation function checkOrientation() { if (isMobile) { const isPortrait = window.innerHeight > window.innerWidth; if (Portrait) { orientationWarning.style.display = 'flex'; gameContainer.style.display = 'none'; } else { orientationWarning.style.display = 'none'; gameContainer.style.display = 'block'; } } } // Start multiplayer game function startMultiplayerGame() { isMultiplayer = true; connectToServer(); // Show room code input roomCodeContainer.style.display = 'flex'; waitingMessage.textContent = 'Connecting to server...'; } // Connect to WebSocket server function connectToServer() { updateConnectionStatus('connecting'); // In a real implementation, you would connect to your actual WebSocket server // For this example, we'll simulate a connection with a delay setTimeout(() => { // Simulate successful connection updateConnectionStatus('connected'); // Generate a random room code roomCode = generateRoomCode(); roomCodeDisplay.textContent = roomCode; waitingMessage.textContent = 'Waiting for opponent to join...'; // Simulate opponent joining after a delay setTimeout(() => { opponentName = 'Opponent' + Math.floor(Math.random() * 1000); opponentNameDisplay.textContent = opponentName; waitingMessage.textContent = 'Opponent joined! Starting game...'; // Start the game after a short delay setTimeout(() => { startGame(); }, 1000); }, 2000); }, 1000); } // Generate a random room code function generateRoomCode() { const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; let result = ''; for (let i = 0; i < 5; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } // Update connection status UI function updateConnectionStatus(status) { const indicator = connectionStatus.querySelector('.indicator'); const text = connectionStatus.querySelector('span'); indicator.className = 'indicator'; switch(status) { case 'connected': indicator.classList.add('connected'); text.textContent = 'Connected'; break; case 'disconnected': indicator.classList.add('disconnected'); text.textContent = 'Disconnected'; break; case 'connecting': indicator.classList.add('connecting'); text.textContent = 'Connecting...'; break; } } // Start game function startGame() { // Reset scores playerScoreValue = 0; aiScoreValue = 0; opponentScoreValue = 0; playerScore.textContent = '0'; aiScore.textContent = '0'; opponentScore.textContent = '0'; // Show/hide appropriate elements based on game mode if (isMultiplayer) { aiPaddle.style.display = 'none'; opponentPaddle.style.display = 'block'; aiScore.style.display = 'none'; opponentScore.style.display = 'block'; opponentNameDisplay.style.display = 'block'; } else { aiPaddle.style.display = 'block'; opponentPaddle.style.display = 'none'; aiScore.style.display = 'block'; opponentScore.style.display = 'none'; opponentNameDisplay.style.display = 'none'; } // Reset positions ballX = gameWidth / 2; ballY = gameHeight / 2; playerPaddleY = (gameHeight - paddleHeight) / 2; aiPaddleY = (gameHeight - paddleHeight) / 2; opponentPaddleY = (gameHeight - paddleHeight) / 2; // Reset ball speed and direction (più lento all'inizio) ballSpeedX = 3 * (Math.random() > 0.5 ? 1 : -1); ballSpeedY = 3 * (Math.random() > 0.5 ? 1 : -1); // Reset power-ups clearPowerUps(); activePowerUp = null; powerUpIndicator.style.display = 'none'; // Hide screens startScreen.style.display = 'none'; roomCodeContainer.style.display = 'none'; gameOverScreen.style.display = 'none'; // Start game loop gameRunning = true; requestAnimationFrame(gameLoop); } // Game loop function gameLoop(timestamp) { if (!gameRunning) return; update(); render(); // Check for power-up expiration if (activePowerUp && timestamp >= powerUpEndTime) { clearPowerUps(); } // Spawn power-ups randomly if (timestamp - lastPowerUpTime > 10000 && Math.random() < 0.01) { spawnPowerUp(); lastPowerUpTime = timestamp; } // In multiplayer mode, send paddle position updates if (isMultiplayer && socket && socket.readyState === WebSocket.OPEN) { // Simulate sending data to server const data = { type: 'paddleUpdate', y: playerPaddleY, room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } requestAnimationFrame(gameLoop); } // Update game state function update() { // Move player paddle if ((keys.ArrowUp || touchUpActive) && playerPaddleY > 0) { playerPaddleY -= paddleSpeed; } if ((keys.ArrowDown || touchDownActive) && playerPaddleY < gameHeight - paddleHeight) { playerPaddleY += paddleSpeed; } // AI or opponent paddle movement if (isMultiplayer) { // In a real multiplayer game, opponent paddle position would come from the server // For this example, we'll just simulate some movement if (Math.random() < 0.02) { const moveDirection = Math.random() > 0.5 ? 1 : -1; opponentPaddleY += paddleSpeed * 0.7 * moveDirection; opponentPaddleY = Math.max(0, Math.min(gameHeight - paddleHeight, opponentPaddleY)); } } else { // AI paddle movement (simple tracking) const aiPaddleCenter = aiPaddleY + paddleHeight / 2; if (aiPaddleCenter < ballY - 15) { aiPaddleY += paddleSpeed * 0.7 * gameSpeed; } else if (aiPaddleCenter > ballY + 15) { aiPaddleY -= paddleSpeed * 0.7 * gameSpeed; } // Keep AI paddle in bounds aiPaddleY = Math.max(0, Math.min(gameHeight - paddleHeight, aiPaddleY)); } // Move ball ballX += ballSpeedX * gameSpeed; ballY += ballSpeedY * gameSpeed; // Ball collision with top and bottom walls if (ballY <= 0 || ballY >= gameHeight - ballSize) { ballSpeedY = -ballSpeedY; createParticles(ballX, ballY, 10, '#ff00e4'); } // Ball collision with player paddle if ( ballX <= 20 + paddleWidth && ballY + ballSize >= playerPaddleY && ballY <= playerPaddleY + paddleHeight ) { // Aumenta la velocità della pallina ad ogni rimbalzo ballSpeedX = Math.abs(ballSpeedX) * speedIncreaseFactor; // Add angle based on where ball hits paddle const hitPosition = (ballY - playerPaddleY) / paddleHeight; ballSpeedY = (hitPosition - 0.5) * 10; createParticles(ballX, ballY, 15, '#00fffc'); // In multiplayer, notify server about the hit if (isMultiplayer && socket) { const data = { type: 'ballHit', x: ballX, y: ballY, speedX: ballSpeedX, speedY: ballSpeedY, room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } // Ball collision with opponent/AI paddle const opponentPaddleToUse = isMultiplayer ? opponentPaddle : aiPaddle; const opponentPaddleYToUse = isMultiplayer ? opponentPaddleY : aiPaddleY; if ( ballX >= gameWidth - 20 - paddleWidth - ballSize && ballY + ballSize >= opponentPaddleYToUse && ballY <= opponentPaddleYToUse + paddleHeight ) { // Aumenta la velocità della pallina ad ogni rimbalzo ballSpeedX = -Math.abs(ballSpeedX) * speedIncreaseFactor; // Add angle based on where ball hits paddle const hitPosition = (ballY - opponentPaddleYToUse) / paddleHeight; ballSpeedY = (hitPosition - 0.5) * 10; createParticles(ballX, ballY, 15, '#ff00e4'); } // Ball out of bounds (score) if (ballX < 0) { if (isMultiplayer) { opponentScoreValue++; opponentScore.textContent = opponentScoreValue; if (socket) { const data = { type: 'score', player: 'opponent', room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } else { aiScoreValue++; aiScore.textContent = aiScoreValue; } resetBall(); const winningScore = isMultiplayer ? 5 : 5; if ((isMultiplayer && opponentScoreValue >= winningScore) || (!isMultiplayer && aiScoreValue >= winningScore)) { endGame(false); } } if (ballX > gameWidth) { if (isMultiplayer) { playerScoreValue++; playerScore.textContent = playerScoreValue; if (socket) { const data = { type: 'score', player: 'player', room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } else { playerScoreValue++; playerScore.textContent = playerScoreValue; } resetBall(); const winningScore = isMultiplayer ? 5 : 5; if (playerScoreValue >= winningScore) { endGame(true); } } // Update power-ups document.querySelectorAll('.power-up').forEach(powerUp => { const rect = powerUp.getBoundingClientRect(); const gameRect = gameContainer.getBoundingClientRect(); const powerUpX = rect.left - gameRect.left; const powerUpY = rect.top - gameRect.top; const powerUpSize = 20; // Check collision with ball if ( ballX + ballSize > powerUpX && ballX < powerUpX + powerUpSize && ballY + ballSize > powerUpY && ballY < powerUpY + powerUpSize ) { const powerUpType = powerUp.classList.contains('speed') ? 'speed' : powerUp.classList.contains('size') ? 'size' : 'freeze'; activatePowerUp(powerUpType); powerUp.remove(); // In multiplayer, notify server about power-up collection if (isMultiplayer && socket) { const data = { type: 'powerUp', powerUpType: powerUpType, room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } }); } // Render game function render() { // Update paddle positions playerPaddle.style.top = playerPaddleY + 'px'; if (isMultiplayer) { opponentPaddle.style.top = opponentPaddleY + 'px'; } else { aiPaddle.style.top = aiPaddleY + 'px'; } // Update ball position ball.style.left = ballX + 'px'; ball.style.top = ballY + 'px'; ball.style.width = ballSize + 'px'; ball.style.height = ballSize + 'px'; // Update particles document.querySelectorAll('.particle').forEach(particle => { const opacity = parseFloat(particle.style.opacity); particle.style.opacity = opacity - 0.02; if (opacity <= 0) { particle.remove(); } }); } // Reset ball after scoring function resetBall() { ballX = gameWidth / 2; ballY = gameHeight / 2; // Resetta la velocità a quella iniziale più lenta ballSpeedX = 3 * (Math.random() > 0.5 ? 1 : -1); ballSpeedY = 3 * (Math.random() > 0.5 ? 1 : -1); gameSpeed = 1; // In multiplayer, notify server about ball reset if (isMultiplayer && socket) { const data = { type: 'ballReset', room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } // End game function endGame(playerWon) { gameRunning = false; if (isMultiplayer) { gameResult.textContent = playerWon ? `YOU WIN! ${opponentName.toUpperCase()} WAS NO MATCH!` : `DEFEAT! ${opponentName.toUpperCase()} TRIUMPHED!`; // Notify server about game end if (socket) { const data = { type: 'gameOver', winner: playerWon ? playerName : opponentName, room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } else { gameResult.textContent = playerWon ? 'YOU WIN! CYBER DOMINATION ACHIEVED!' : 'DEFEAT! THE AI HAS TRIUMPHED!'; } gameOverScreen.style.display = 'flex'; } // Create explosion particles function createParticles(x, y, count, color) { for (let i = 0; i < count; i++) { const particle = document.createElement('div'); particle.className = 'particle'; particle.style.left = x + 'px'; particle.style.top = y + 'px'; particle.style.backgroundColor = color; particle.style.opacity = '1'; // Random direction and speed const angle = Math.random() * Math.PI * 2; const speed = Math.random() * 3 + 1; const vx = Math.cos(angle) * speed; const vy = Math.sin(angle) * speed; gameContainer.appendChild(particle); // Animate particle let frame = 0; const animateParticle = () => { frame++; const currentX = parseFloat(particle.style.left); const currentY = parseFloat(particle.style.top); particle.style.left = (currentX + vx) + 'px'; particle.style.top = (currentY + vy) + 'px'; if (frame < 30) { requestAnimationFrame(animateParticle); } }; animateParticle(); } } // Spawn power-up function spawnPowerUp() { if (activePowerUp) return; const powerUp = powerUps[Math.floor(Math.random() * powerUps.length)]; const powerUpElement = document.createElement('div'); powerUpElement.className = `power-up ${powerUp.type}`; powerUpElement.style.left = (Math.random() * (gameWidth - 50) + 25) + 'px'; powerUpElement.style.top = (Math.random() * (gameHeight - 50) + 25) + 'px'; powerUpElement.style.backgroundColor = powerUp.color; powerUpElement.style.boxShadow = `0 0 10px ${powerUp.color}`; gameContainer.appendChild(powerUpElement); // Remove power-up after 5 seconds if not collected setTimeout(() => { if (powerUpElement.parentNode) { powerUpElement.remove(); } }, 5000); // In multiplayer, notify server about power-up spawn if (isMultiplayer && socket) { const rect = powerUpElement.getBoundingClientRect(); const gameRect = gameContainer.getBoundingClientRect(); const x = rect.left - gameRect.left; const y = rect.top - gameRect.top; const data = { type: 'powerUpSpawn', powerUpType: powerUp.type, x: x, y: y, room: roomCode }; // In a real implementation: socket.send(JSON.stringify(data)); } } // Activate power-up function activatePowerUp(type) { clearPowerUps(); const powerUp = powerUps.find(p => p.type === type); if (!powerUp) return; powerUp.effect(); activePowerUp = type; powerUpEndTime = performance.now() + powerUp.duration; // Show indicator powerUpIndicator.textContent = `POWER UP: ${type.toUpperCase()}!`; powerUpIndicator.style.color = powerUp.color; powerUpIndicator.style.display = 'block'; powerUpIndicator.classList.add('glow'); // Remove indicator after duration setTimeout(() => { powerUpIndicator.style.display = 'none'; powerUpIndicator.classList.remove('glow'); }, powerUp.duration); } // Clear active power-ups function clearPowerUps() { if (!activePowerUp) return; // Reset game speed gameSpeed = 1; // Reset paddle size playerPaddle.style.height = paddleHeight + 'px'; // Reset opponent/AI paddle opacity if (isMultiplayer) { opponentPaddle.style.opacity = '1'; } else { aiPaddle.style.opacity = '1'; } activePowerUp = null; } // Handle WebSocket messages function handleSocketMessage(event) { try { const data = JSON.parse(event.data); switch(data.type) { case 'paddleUpdate': if (data.player !== playerName) { opponentPaddleY = data.y; } break; case 'ballUpdate': ballX = data.x; ballY = data.y; ballSpeedX = data.speedX; ballSpeedY = data.speedY; break; case 'powerUpSpawn': // Spawn power-up at specified position const powerUpElement = document.createElement('div'); powerUpElement.className = `power-up ${data.powerUpType}`; powerUpElement.style.left = data.x + 'px'; powerUpElement.style.top = data.y + 'px'; powerUpElement.style.backgroundColor = powerUps.find(p => p.type === data.powerUpType).color; powerUpElement.style.boxShadow = `0 0 10px ${powerUps.find(p => p.type === data.powerUpType).color}`; gameContainer.appendChild(powerUpElement); break; case 'score': if (data.player === 'player') { playerScoreValue = data.score; playerScore.textContent = playerScoreValue; } else { opponentScoreValue = data.score; opponentScore.textContent = opponentScoreValue; } break; case 'gameOver': gameRunning = false; gameResult.textContent = data.winner === playerName ? 'YOU WIN! CYBER DOMINATION ACHIEVED!' : 'DEFEAT! YOUR OPPONENT TRIUMPHED!'; gameOverScreen.style.display = 'flex'; break; case 'playerJoined': opponentName = data.playerName; opponentNameDisplay.textContent = opponentName; waitingMessage.textContent = `${opponentName} has joined! Starting game...`; setTimeout(() => { startGame(); }, 1000); break; } } catch (e) { console.error('Error processing message:', e); } } // Keyboard input const keys = {}; document.addEventListener('keydown', (e) => { keys[e.key] = true; }); document.addEventListener('keyup', (e) => { keys[e.key] = false; }); }); </script> <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> </html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Cyber Pong Explosion - Online Multiplayer</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
touch-action: manipulation;
}
body {
background-color: #0a0a1a;
color: #00fffc;
font-family: 'Orbitron', 'Arial', sans-serif;
overflow: hidden;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
-webkit-tap-highlight-color: transparent;
}
@font-face {
font-family: 'Orbitron';
src: url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
}
.game-container {
position: relative;
width: 100%;
max-width: 800px;
height: 100vh;
max-height: 500px;
border: 3px solid #00fffc;
box-shadow: 0 0 20px #00fffc, inset 0 0 20px rgba(0, 255, 252, 0.3);
border-radius: 10px;
overflow: hidden;
background: radial-gradient(circle at center, #0a0a1a 0%, #000 100%);
}
@media (max-width: 600px) {
.game-container {
border-radius: 0;
border: none;
max-height: none;
height: 100vh;
}
}
.paddle {
position: absolute;
width: 15px;
height: 100px;
background: linear-gradient(to bottom, #00fffc, #0084ff);
border-radius: 5px;
box-shadow: 0 0 10px #00fffc;
}
@media (max-width: 600px) {
.paddle {
width: 12px;
height: 80px;
}
}
#playerPaddle {
left: 20px;
}
#aiPaddle, #opponentPaddle {
right: 20px;
}
.ball {
position: absolute;
width: 20px;
height: 20px;
background: #ff00e4;
border-radius: 50%;
box-shadow: 0 0 15px #ff00e4;
}
@media (max-width: 600px) {
.ball {
width: 16px;
height: 16px;
}
}
.score {
position: absolute;
top: 20px;
font-size: 2rem;
font-weight: bold;