Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Pong Game</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100vh; | |
| background-color: #222; | |
| font-family: Arial, sans-serif; | |
| overflow: hidden; | |
| } | |
| #game-container { | |
| position: relative; | |
| width: 800px; | |
| height: 500px; | |
| border: 2px solid #fff; | |
| background-color: #000; | |
| overflow: hidden; | |
| } | |
| #ball { | |
| position: absolute; | |
| width: 20px; | |
| height: 20px; | |
| background-color: #fff; | |
| border-radius: 50%; | |
| } | |
| .paddle { | |
| position: absolute; | |
| width: 15px; | |
| height: 100px; | |
| background-color: #fff; | |
| } | |
| #player-paddle { | |
| left: 30px; | |
| } | |
| #ai-paddle { | |
| right: 30px; | |
| } | |
| #center-line { | |
| position: absolute; | |
| top: 0; | |
| left: 50%; | |
| width: 4px; | |
| height: 100%; | |
| background-color: rgba(255, 255, 255, 0.2); | |
| transform: translateX(-50%); | |
| } | |
| #score-display { | |
| position: absolute; | |
| top: 20px; | |
| left: 0; | |
| right: 0; | |
| text-align: center; | |
| font-size: 40px; | |
| color: rgba(255, 255, 255, 0.5); | |
| z-index: 1; | |
| } | |
| #player-score, #ai-score { | |
| display: inline-block; | |
| width: 100px; | |
| } | |
| #start-screen { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.7); | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 2; | |
| } | |
| #game-over { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.7); | |
| display: none; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 2; | |
| } | |
| button { | |
| padding: 12px 24px; | |
| font-size: 18px; | |
| background-color: #4CAF50; | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| margin-top: 20px; | |
| } | |
| button:hover { | |
| background-color: #45a049; | |
| } | |
| h1, h2 { | |
| color: white; | |
| margin: 10px 0; | |
| } | |
| .difficulty { | |
| margin-top: 20px; | |
| } | |
| .difficulty button { | |
| margin: 0 10px; | |
| padding: 8px 16px; | |
| } | |
| #easy { background-color: #4CAF50; } | |
| #medium { background-color: #ff9800; } | |
| #hard { background-color: #f44336; } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="game-container"> | |
| <div id="score-display"> | |
| <span id="player-score">0</span> | |
| <span id="ai-score">0</span> | |
| </div> | |
| <div id="center-line"></div> | |
| <div id="ball"></div> | |
| <div id="player-paddle" class="paddle"></div> | |
| <div id="ai-paddle" class="paddle"></div> | |
| <div id="start-screen"> | |
| <h1>PONG</h1> | |
| <h2>Select Difficulty</h2> | |
| <div class="difficulty"> | |
| <button id="easy">Easy</button> | |
| <button id="medium">Medium</button> | |
| <button id="hard">Hard</button> | |
| </div> | |
| </div> | |
| <div id="game-over"> | |
| <h1 id="game-result">Game Over</h1> | |
| <button id="restart">Play Again</button> | |
| </div> | |
| </div> | |
| <script> | |
| // Game elements | |
| const ball = document.getElementById('ball'); | |
| const playerPaddle = document.getElementById('player-paddle'); | |
| const aiPaddle = document.getElementById('ai-paddle'); | |
| const playerScoreElem = document.getElementById('player-score'); | |
| const aiScoreElem = document.getElementById('ai-score'); | |
| const startScreen = document.getElementById('start-screen'); | |
| const gameOverScreen = document.getElementById('game-over'); | |
| const gameResult = document.getElementById('game-result'); | |
| const restartButton = document.getElementById('restart'); | |
| const container = document.getElementById('game-container'); | |
| // Difficulty buttons | |
| const easyButton = document.getElementById('easy'); | |
| const mediumButton = document.getElementById('medium'); | |
| const hardButton = document.getElementById('hard'); | |
| // Game state | |
| let ballX = 400; | |
| let ballY = 250; | |
| let ballSpeedX = 5; | |
| let ballSpeedY = 5; | |
| let playerY = 200; | |
| let aiY = 200; | |
| let playerScore = 0; | |
| let aiScore = 0; | |
| let aiSpeed = 3; // Default speed, will be set based on difficulty | |
| let maxScore = 5; | |
| let ballSize = 20; | |
| let paddleHeight = 100; | |
| let paddleWidth = 15; | |
| let isPlaying = false; | |
| let animationFrameId; | |
| // Initial positioning | |
| function initPositions() { | |
| ballX = container.offsetWidth / 2; | |
| ballY = container.offsetHeight / 2; | |
| playerY = container.offsetHeight / 2 - paddleHeight / 2; | |
| aiY = container.offsetHeight / 2 - paddleHeight / 2; | |
| ball.style.left = `${ballX - ballSize / 2}px`; | |
| ball.style.top = `${ballY - ballSize / 2}px`; | |
| playerPaddle.style.top = `${playerY}px`; | |
| aiPaddle.style.top = `${aiY}px`; | |
| } | |
| // Initialize game | |
| function init() { | |
| // Set paddle height and positioning | |
| playerPaddle.style.height = `${paddleHeight}px`; | |
| aiPaddle.style.height = `${paddleHeight}px`; | |
| initPositions(); | |
| // Reset scores | |
| playerScore = 0; | |
| aiScore = 0; | |
| playerScoreElem.textContent = playerScore; | |
| aiScoreElem.textContent = aiScore; | |
| } | |
| // Start game with selected difficulty | |
| function startGame(difficulty) { | |
| switch(difficulty) { | |
| case 'easy': | |
| aiSpeed = 2.5; | |
| break; | |
| case 'medium': | |
| aiSpeed = 4; | |
| break; | |
| case 'hard': | |
| aiSpeed = 5.5; | |
| break; | |
| default: | |
| aiSpeed = 3; | |
| } | |
| startScreen.style.display = 'none'; | |
| isPlaying = true; | |
| gameLoop(); | |
| } | |
| // Main game loop | |
| function gameLoop() { | |
| if (!isPlaying) return; | |
| updateBall(); | |
| updateAI(); | |
| checkCollision(); | |
| checkScore(); | |
| animationFrameId = requestAnimationFrame(gameLoop); | |
| } | |
| // Update ball position | |
| function updateBall() { | |
| ballX += ballSpeedX; | |
| ballY += ballSpeedY; | |
| // Wall collision (top/bottom) | |
| if (ballY <= 0 || ballY >= container.offsetHeight) { | |
| ballSpeedY = -ballSpeedY; | |
| // Ensure ball doesn't get stuck | |
| if (ballY <= 0) { | |
| ballY = 1; | |
| } else { | |
| ballY = container.offsetHeight - 1; | |
| } | |
| } | |
| ball.style.left = `${ballX - ballSize / 2}px`; | |
| ball.style.top = `${ballY - ballSize / 2}px`; | |
| } | |
| // Update AI paddle position | |
| function updateAI() { | |
| const aiPaddleCenter = aiY + paddleHeight / 2; | |
| // Add some delay for easier difficulty | |
| if (ballX > container.offsetWidth / 2) { | |
| if (aiPaddleCenter < ballY - 10) { | |
| aiY += aiSpeed; | |
| } else if (aiPaddleCenter > ballY + 10) { | |
| aiY -= aiSpeed; | |
| } | |
| } | |
| // Keep paddle within bounds | |
| if (aiY < 0) aiY = 0; | |
| if (aiY > container.offsetHeight - paddleHeight) aiY = container.offsetHeight - paddleHeight; | |
| aiPaddle.style.top = `${aiY}px`; | |
| } | |
| // Check for paddle collisions | |
| function checkCollision() { | |
| // Player paddle collision | |
| if ( | |
| ballX <= 30 + paddleWidth + ballSize / 2 && | |
| ballX >= 30 && | |
| ballY >= playerY && | |
| ballY <= playerY + paddleHeight | |
| ) { | |
| // Calculate angle based on where ball hits paddle | |
| let hitPosition = (ballY - (playerY + paddleHeight / 2)) / (paddleHeight / 2); | |
| let angle = hitPosition * (Math.PI / 4); // Max 45 degree angle | |
| // Increase speed slightly with each hit | |
| let speed = Math.sqrt(ballSpeedX * ballSpeedX + ballSpeedY * ballSpeedY); | |
| speed = Math.min(speed + 0.2, 12); // Cap max speed | |
| ballSpeedX = Math.cos(angle) * speed; | |
| ballSpeedY = Math.sin(angle) * speed; | |
| // Play sound (add sound effects if you want to enhance the game) | |
| // playSound('paddle'); | |
| } | |
| // AI paddle collision | |
| if ( | |
| ballX >= container.offsetWidth - 30 - paddleWidth - ballSize / 2 && | |
| ballX <= container.offsetWidth - 30 && | |
| ballY >= aiY && | |
| ballY <= aiY + paddleHeight | |
| ) { | |
| // Calculate angle based on where ball hits paddle | |
| let hitPosition = (ballY - (aiY + paddleHeight / 2)) / (paddleHeight / 2); | |
| let angle = hitPosition * (Math.PI / 4); // Max 45 degree angle | |
| // Increase speed slightly with each hit | |
| let speed = Math.sqrt(ballSpeedX * ballSpeedX + ballSpeedY * ballSpeedY); | |
| speed = Math.min(speed + 0.2, 12); // Cap max speed | |
| ballSpeedX = -Math.cos(angle) * speed; | |
| ballSpeedY = Math.sin(angle) * speed; | |
| // Play sound | |
| // playSound('paddle'); | |
| } | |
| } | |
| // Check if a player scored | |
| function checkScore() { | |
| // Ball went past the player's paddle | |
| if (ballX < 0) { | |
| aiScore++; | |
| aiScoreElem.textContent = aiScore; | |
| resetBall(1); | |
| // playSound('score'); | |
| if (aiScore >= maxScore) { | |
| endGame(false); | |
| } | |
| } | |
| // Ball went past the AI's paddle | |
| if (ballX > container.offsetWidth) { | |
| playerScore++; | |
| playerScoreElem.textContent = playerScore; | |
| resetBall(-1); | |
| // playSound('score'); | |
| if (playerScore >= maxScore) { | |
| endGame(true); | |
| } | |
| } | |
| } | |
| // Reset ball after scoring | |
| function resetBall(direction) { | |
| ballX = container.offsetWidth / 2; | |
| ballY = container.offsetHeight / 2; | |
| // Start ball in the direction of who just scored | |
| let speed = 5; // Reset to initial speed | |
| let angle = (Math.random() - 0.5) * (Math.PI / 4); // Random angle up to +/- 45 degrees | |
| ballSpeedX = direction * Math.cos(angle) * speed; | |
| ballSpeedY = Math.sin(angle) * speed; | |
| } | |
| // End game and show results | |
| function endGame(playerWon) { | |
| isPlaying = false; | |
| cancelAnimationFrame(animationFrameId); | |
| if (playerWon) { | |
| gameResult.textContent = 'You Win!'; | |
| } else { | |
| gameResult.textContent = 'AI Wins!'; | |
| } | |
| gameOverScreen.style.display = 'flex'; | |
| } | |
| // Mouse/touch movement for the player paddle | |
| function handleMouseMove(e) { | |
| if (!isPlaying) return; | |
| // Get relative mouse position | |
| const containerRect = container.getBoundingClientRect(); | |
| let mouseY; | |
| if (e.type === 'mousemove') { | |
| mouseY = e.clientY - containerRect.top; | |
| } else if (e.type === 'touchmove') { | |
| mouseY = e.touches[0].clientY - containerRect.top; | |
| e.preventDefault(); // Prevent scrolling | |
| } | |
| // Move paddle and keep within bounds | |
| playerY = mouseY - paddleHeight / 2; | |
| if (playerY < 0) playerY = 0; | |
| if (playerY > container.offsetHeight - paddleHeight) playerY = container.offsetHeight - paddleHeight; | |
| playerPaddle.style.top = `${playerY}px`; | |
| } | |
| // Event listeners | |
| easyButton.addEventListener('click', () => startGame('easy')); | |
| mediumButton.addEventListener('click', () => startGame('medium')); | |
| hardButton.addEventListener('click', () => startGame('hard')); | |
| restartButton.addEventListener('click', () => { | |
| gameOverScreen.style.display = 'none'; | |
| startScreen.style.display = 'flex'; | |
| init(); | |
| }); | |
| // Mouse and touch events for paddle movement | |
| container.addEventListener('mousemove', handleMouseMove); | |
| container.addEventListener('touchmove', handleMouseMove); | |
| // Initialize the game | |
| init(); | |
| </script> | |
| </body> | |
| </html> |