Back to Game

Pong - Source Code

Play Game
JavaScript
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.