PHP

PHP Snake Game with Leaderboard

Build the classic Snake game with smooth animations, increasing difficulty, and a PHP-powered server-side leaderboard.

PHPJavaScriptCanvasGameAnimation

Thumbnail for PHP Snake Game with Leaderboard

Overview

Build the classic Snake game with buttery smooth rendering on Canvas, progressive speed increases, and a PHP-powered high scores leaderboard.

Game UI (index.php)

php
<?php
$scores = [];
if (file_exists('scores.json')) {
    $scores = json_decode(file_get_contents('scores.json'), true);
    usort($scores, fn($a,$b) => $b['score'] - $a['score']);
    $scores = array_slice($scores, 0, 10);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Snake Game</title>
  <style>
    body { margin: 0; background: #0a0a23; color: #fff; font-family: sans-serif; display: flex; justify-content: center; gap: 2rem; padding: 2rem; }
    canvas { border: 2px solid #6c63ff; border-radius: 8px; }
    .sidebar { width: 220px; }
    .score-display { font-size: 2.5rem; font-weight: bold; color: #6c63ff; text-align: center; margin-bottom: 1rem; }
    .leaderboard { background: #1a1a3e; border-radius: 12px; padding: 1rem; }
    .leaderboard h3 { text-align: center; margin-bottom: 1rem; }
    .game-over { position: fixed; inset: 0; background: rgba(0,0,0,0.8); display: none; justify-content: center; align-items: center; flex-direction: column; }
    .game-over h2 { font-size: 3rem; animation: popIn 0.5s; }
    @keyframes popIn { from { transform: scale(0); } to { transform: scale(1); } }
  </style>
</head>
<body>
  <div class="sidebar">
    <div class="score-display" id="score">0</div>
    <div class="leaderboard">
      <h3>������ Top 10</h3>
      <ol style="padding-left:1.2rem">
        <?php foreach ($scores as $s): ?><li><?= htmlspecialchars($s['name']) ?><?= $s['score'] ?></li><?php endforeach; ?>
        <?php if (empty($scores)): ?><li>No scores yet</li><?php endif; ?>
      </ol>
    </div>
  </div>
  <canvas id="game" width="400" height="400"></canvas>
  <div class="game-over" id="gameover">
    <h2>Game Over!</h2>
    <p style="font-size:1.4rem;margin:1rem">Score: <span id="final"></span></p>
    <input id="name" placeholder="Your name" style="padding:10px;border-radius:8px;border:none;font-size:1rem">
    <button onclick="submitScore()" style="margin-top:1rem;padding:10px 30px;background:#6c63ff;color:#fff;border:none;border-radius:8px;cursor:pointer">Save Score</button>
  </div>
  <script>
  const canvas = document.getElementById('game'), ctx = canvas.getContext('2d');
  const grid = 20, cols = canvas.width/grid, rows = canvas.height/grid;
  let snake = [{x:10,y:10}], dir = {x:1,y:0}, food, score = 0, speed = 100, gameLoop;
  function spawn() { food = { x: Math.floor(Math.random()*cols), y: Math.floor(Math.random()*rows) }; }
  spawn();
  document.addEventListener('keydown', e => {
    const map = { ArrowUp:{x:0,y:-1}, ArrowDown:{x:0,y:1}, ArrowLeft:{x:-1,y:0}, ArrowRight:{x:1,y:0} };
    if (map[e.key] && (map[e.key].x + dir.x !== 0 || map[e.key].y + dir.y !== 0)) dir = map[e.key];
  });
  function update() {
    const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
    if (head.x < 0 || head.x >= cols || head.y < 0 || head.y >= rows || snake.some(s => s.x === head.x && s.y === head.y)) return gameOver();
    snake.unshift(head);
    if (head.x === food.x && head.y === food.y) { score += 10; document.getElementById('score').textContent = score; spawn(); clearInterval(gameLoop); speed = Math.max(50, speed - 2); gameLoop = setInterval(update, speed); }
    else { snake.pop(); }
    draw();
  }
  function draw() {
    ctx.fillStyle = '#0a0a23'; ctx.fillRect(0, 0, 400, 400);
    ctx.fillStyle = '#ff6b6b'; ctx.fillRect(food.x*grid+2, food.y*grid+2, grid-4, grid-4);
    snake.forEach((s, i) => { ctx.fillStyle = i === 0 ? '#6c63ff' : '#48dbfb'; ctx.fillRect(s.x*grid+1, s.y*grid+1, grid-2, grid-2); });
  }
  function gameOver() { clearInterval(gameLoop); document.getElementById('final').textContent = score; document.getElementById('gameover').style.display = 'flex'; }
  async function submitScore() {
    const name = document.getElementById('name').value || 'Anonymous';
    await fetch('save_score.php', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ name, score }) });
    location.reload();
  }
  gameLoop = setInterval(update, speed); draw();
  </script>
</body>
</html>

Score Saver (save_score.php)

php
<?php
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$scores = file_exists('scores.json') ? json_decode(file_get_contents('scores.json'), true) : [];
$scores[] = ['name' => htmlspecialchars(substr($input['name'] ?? 'Anon', 0, 20)), 'score' => (int)($input['score'] ?? 0), 'date' => date('Y-m-d H:i')];
file_put_contents('scores.json', json_encode($scores));
echo json_encode(['ok' => true]);
?>

Technologies

- PHP — leaderboard, score persistence - HTML5 Canvas — game rendering - JavaScript — game loop, collision detection

Related Projects

Comments (0)

Leave a Comment

No comments yet. Be the first to comment!