<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Single Player Pong</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background: black;
height: 100vh;
overflow: hidden;
}
canvas {
border: 2px solid white;
}
</style>
</head>
<body>
<canvas id="pong"></canvas>
<script>
const canvas = document.getElementById('pong');
const ctx = canvas.getContext('2d');
// Set canvas size to fit the screen
canvas.width = window.innerWidth * 0.9;
canvas.height = window.innerHeight * 0.8;
const paddleWidth = 10;
const paddleHeight = 100;
const ballSize = 10;
const maxScore = 21;
const player = { x: 10, y: canvas.height / 2 - paddleHeight / 2, score: 0 };
const computer = { x: canvas.width - 20, y: canvas.height / 2 - paddleHeight / 2, score: 0 };
const ball = { x: canvas.width / 2, y: canvas.height / 2, dx: 4, dy: 4, speed: 4 };
let touchY = player.y; // Track touch position for the player's paddle
let gameOver = false;
let countdown = 0;
let rallyCount = 0; // Counts consecutive hits to increase speed
const drawRect = (x, y, width, height, color) => {
ctx.fillStyle = color;
ctx.fillRect(x, y, width, height);
};
const drawCircle = (x, y, radius, color) => {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
};
const drawText = (text, x, y, color, fontSize = "30px") => {
ctx.fillStyle = color;
ctx.font = `${fontSize} Arial`;
ctx.fillText(text, x, y);
};
const resetBall = () => {
ball.x = canvas.width / 2;
ball.y = canvas.height / 2;
// Ensure the ball launches with a random angle between 0 and 45 degrees
const angle = (Math.random() * Math.PI) / 4; // Random angle between 0 and 45 degrees
ball.speed = 4; // Reset speed to initial value
rallyCount = 0; // Reset rally count
ball.dx = ball.speed * (Math.random() > 0.5 ? 1 : -1);
ball.dy = ball.speed * Math.tan(angle) * (Math.random() > 0.5 ? 1 : -1);
};
const startCountdown = (callback) => {
countdown = 3;
const interval = setInterval(() => {
countdown--;
if (countdown < 0) {
clearInterval(interval);
callback(); // Resume the game
}
}, 1000);
};
const checkWinCondition = () => {
if (player.score >= maxScore || computer.score >= maxScore) {
gameOver = true;
}
};
const update = () => {
if (gameOver) return;
// Allow paddle movement even during countdown
player.y += (touchY - player.y) * 0.2;
// Prevent paddles from going out of bounds
player.y = Math.max(Math.min(player.y, canvas.height - paddleHeight), 0);
computer.y = Math.max(Math.min(computer.y, canvas.height - paddleHeight), 0);
if (countdown > 0) return; // Pause ball and AI during countdown
// Ball movement
ball.x += ball.dx;
ball.y += ball.dy;
// Bounce off top and bottom walls
if (ball.y <= 0 || ball.y + ballSize >= canvas.height) {
ball.dy *= -1;
}
// Bounce off paddles
if (
ball.x <= player.x + paddleWidth &&
ball.y >= player.y &&
ball.y <= player.y + paddleHeight
) {
ball.dx = Math.abs(ball.dx); // Ensure the ball moves to the right
rallyCount++;
ball.speed += 0.5; // Increase speed slightly after each rally
ball.dx = Math.sign(ball.dx) * ball.speed;
ball.dy = Math.sign(ball.dy) * ball.speed;
}
if (
ball.x + ballSize >= computer.x &&
ball.y >= computer.y &&
ball.y <= computer.y + paddleHeight
) {
ball.dx = -Math.abs(ball.dx); // Ensure the ball moves to the left
rallyCount++;
ball.speed += 0.5; // Increase speed slightly after each rally
ball.dx = Math.sign(ball.dx) * ball.speed;
ball.dy = Math.sign(ball.dy) * ball.speed;
}
// Scoring
if (ball.x < 0) {
computer.score++;
resetBall();
startCountdown(() => {});
}
if (ball.x > canvas.width) {
player.score++;
resetBall();
startCountdown(() => {});
}
// Prevent the ball from getting stuck behind the paddle
if (ball.x < 0 && ball.dx < 0) {
resetBall();
computer.score++;
startCountdown(() => {});
}
// AI speed and behavior
const computerSpeed = 3;
if (computer.y + paddleHeight / 2 < ball.y) {
computer.y += computerSpeed;
} else {
computer.y -= computerSpeed;
}
checkWinCondition();
};
const render = () => {
drawRect(0, 0, canvas.width, canvas.height, "black");
drawRect(player.x, player.y, paddleWidth, paddleHeight, "white");
drawRect(computer.x, computer.y, paddleWidth, paddleHeight, "white");
drawCircle(ball.x, ball.y, ballSize, "white");
drawText(player.score, canvas.width / 4, 50, "white");
drawText(computer.score, (canvas.width * 3) / 4, 50, "white");
if (gameOver) {
const winner = player.score >= maxScore ? "You Win!" : "AI Wins!";
drawText(winner, canvas.width / 2 - 100, canvas.height / 2, "red");
drawText("Reload to Play Again", canvas.width / 2 - 150, canvas.height / 2 + 50, "white");
} else if (countdown > 0) {
drawText(countdown, canvas.width / 2 - 15, canvas.height / 2, "white", "50px");
}
};
const gameLoop = () => {
update();
render();
if (!gameOver) requestAnimationFrame(gameLoop);
};
// Handle touch input
canvas.addEventListener("touchmove", (event) => {
const touch = event.touches[0];
const rect = canvas.getBoundingClientRect();
touchY = touch.clientY - rect.top - paddleHeight / 2;
});
// Start the initial countdown
startCountdown(() => {
gameLoop();
});
</script>
</body>
</html>
Comments
Post a Comment