simple-pong-game / index.html
julien-c's picture
julien-c HF Staff
Add index.html
7e9a32b verified
<!DOCTYPE html>
<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>