const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 400;
const PADDLE_WIDTH = 10;
const PADDLE_HEIGHT = 80;
const BALL_SIZE = 10;
let gameState = {
playerY: CANVAS_HEIGHT / 2 - PADDLE_HEIGHT / 2,
aiY: CANVAS_HEIGHT / 2 - PADDLE_HEIGHT / 2,
ballX: CANVAS_WIDTH / 2,
ballY: CANVAS_HEIGHT / 2,
ballVelX: 5,
ballVelY: 3,
playerScore: 0,
aiScore: 0
};
function updateAI() {
const aiCenter = gameState.aiY + PADDLE_HEIGHT / 2;
const ballCenter = gameState.ballY;
const aiSpeed = 7;
const predictedY = gameState.ballY + (gameState.ballVelY *
((CANVAS_WIDTH - 30 - gameState.ballX) / Math.abs(gameState.ballVelX)));
const targetY = Math.max(PADDLE_HEIGHT / 2,
Math.min(CANVAS_HEIGHT - PADDLE_HEIGHT / 2, predictedY));
if (aiCenter < targetY - 5) {
gameState.aiY = Math.min(CANVAS_HEIGHT - PADDLE_HEIGHT, gameState.aiY + aiSpeed);
} else if (aiCenter > targetY + 5) {
gameState.aiY = Math.max(0, gameState.aiY - aiSpeed);
}
}
function updateBall() {
gameState.ballX += gameState.ballVelX;
gameState.ballY += gameState.ballVelY;
if (gameState.ballY <= BALL_SIZE / 2 || gameState.ballY >= CANVAS_HEIGHT - BALL_SIZE / 2) {
gameState.ballVelY = -gameState.ballVelY;
}
if (gameState.ballX <= 30 + PADDLE_WIDTH &&
gameState.ballY >= gameState.playerY &&
gameState.ballY <= gameState.playerY + PADDLE_HEIGHT) {
gameState.ballVelX = -gameState.ballVelX;
const relativeIntersectY = (gameState.playerY + PADDLE_HEIGHT / 2) - gameState.ballY;
gameState.ballVelY = -(relativeIntersectY / (PADDLE_HEIGHT / 2)) * 5;
}
if (gameState.ballX >= CANVAS_WIDTH - 30 - PADDLE_WIDTH &&
gameState.ballY >= gameState.aiY &&
gameState.ballY <= gameState.aiY + PADDLE_HEIGHT) {
gameState.ballVelX = -gameState.ballVelX;
const relativeIntersectY = (gameState.aiY + PADDLE_HEIGHT / 2) - gameState.ballY;
gameState.ballVelY = -(relativeIntersectY / (PADDLE_HEIGHT / 2)) * 5;
}
if (gameState.ballX < 0) {
gameState.aiScore++;
resetBall();
}
if (gameState.ballX > CANVAS_WIDTH) {
gameState.playerScore++;
resetBall();
}
}
function resetBall() {
gameState.ballX = CANVAS_WIDTH / 2;
gameState.ballY = CANVAS_HEIGHT / 2;
gameState.ballVelX = gameState.ballVelX > 0 ? -5 : 5;
gameState.ballVelY = (Math.random() - 0.5) * 6;
}
function draw() {
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
ctx.fillStyle = '#fff';
ctx.fillRect(20, gameState.playerY, PADDLE_WIDTH, PADDLE_HEIGHT);
ctx.fillRect(CANVAS_WIDTH - 30, gameState.aiY, PADDLE_WIDTH, PADDLE_HEIGHT);
ctx.fillRect(gameState.ballX - BALL_SIZE / 2, gameState.ballY - BALL_SIZE / 2, BALL_SIZE, BALL_SIZE);
ctx.font = '48px Arial';
ctx.textAlign = 'center';
ctx.fillText(gameState.playerScore, CANVAS_WIDTH / 4, 60);
ctx.fillText(gameState.aiScore, 3 * CANVAS_WIDTH / 4, 60);
}
function gameLoop() {
updateAI();
updateBall();
draw();
requestAnimationFrame(gameLoop);
}
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowUp' && gameState.playerY > 0) {
gameState.playerY -= 20;
}
if (e.key === 'ArrowDown' && gameState.playerY < CANVAS_HEIGHT - PADDLE_HEIGHT) {
gameState.playerY += 20;
}
});
gameLoop();This code demonstrates the core game logic. The actual implementation may include additional features and optimizations.