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> |