Chappy Game

<!DOCTYPE html> <html lang=”en”> <head> <meta charset=”UTF-8″> <meta name=”viewport” content=”width=device-width, initial-scale=1.0″> <title>Flappy Bird Game</title> <link href=”https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css” rel=”stylesheet”> <style> body { margin: 0; padding: 0; overflow: hidden; background: #2c3e50; font-family: ‘Arial’, sans-serif; } canvas { display: block; margin: 0 auto; } .game-container { position: relative; width: 100%; max-width: 400px; margin: 0 auto; } .start-screen, .game-over-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.7); color: white; z-index: 10; } .hidden { display: none; } .btn { padding: 10px 20px; border: none; border-radius: 5px; margin-top: 20px; font-size: 1.2rem; cursor: pointer; background-color: #f1c40f; color: #2c3e50; font-weight: bold; transition: transform 0.2s; } .btn:hover { transform: scale(1.05); } </style> </head> <body class=”flex flex-col items-center justify-center min-h-screen p-4″> <div class=”text-center mb-4″> <h1 class=”text-3xl font-bold text-white mb-2″>Flappy Bird</h1> <p class=”text-lg text-white”>Press spacebar or click to flap!</p> </div> <div class=”game-container”> <canvas id=”game-canvas” width=”320″ height=”480″></canvas> <div id=”start-screen” class=”start-screen”> <h2 class=”text-2xl font-bold mb-2″>Flappy Bird</h2> <p class=”mb-4″>Click or press Spacebar to flap the bird</p> <button id=”start-button” class=”btn”>Start Game</button> </div> <div id=”game-over-screen” class=”game-over-screen hidden”> <h2 class=”text-2xl font-bold mb-2″>Game Over!</h2> <p class=”mb-2″>Your Score: <span id=”final-score”>0</span></p> <p class=”mb-2″>Best Score: <span id=”best-score”>0</span></p> <button id=”restart-button” class=”btn”>Play Again</button> </div> </div> <script> document.addEventListener(‘DOMContentLoaded’, () => { // Canvas setup const canvas = document.getElementById(‘game-canvas’); const ctx = canvas.getContext(‘2d’); const startScreen = document.getElementById(‘start-screen’); const gameOverScreen = document.getElementById(‘game-over-screen’); const startButton = document.getElementById(‘start-button’); const restartButton = document.getElementById(‘restart-button’); const finalScoreElement = document.getElementById(‘final-score’); const bestScoreElement = document.getElementById(‘best-score’); // Game variables let gameRunning = false; let gameOver = false; let score = 0; let bestScore = localStorage.getItem(‘flappyBirdBestScore’) || 0; // Bird properties const bird = { x: 50, y: canvas.height / 2 – 10, width: 30, height: 24, gravity: 0.5, jump: -8, velocity: 0, rotation: 0 }; // Pipe properties const pipeGap = 120; const pipeWidth = 60; let pipes = []; const pipeInterval = 1500; // milliseconds let lastPipeTime = 0; // Game constants const groundHeight = 80; const skyColor = “#71c5cf”; const groundColor = “#ded895”; const pipeColor = “#73bf2e”; const pipeBorderColor = “#558022”; const birdColors = { body: “#f7ec4f”, beak: “#ff9000”, eye: “#000000”, wing: “#f8a72a” }; // Game state let animationFrameId; let lastTimestamp = 0; // Draw functions function drawSky() { ctx.fillStyle = skyColor; ctx.fillRect(0, 0, canvas.width, canvas.height – groundHeight); } function drawGround() { ctx.fillStyle = groundColor; ctx.fillRect(0, canvas.height – groundHeight, canvas.width, groundHeight); // Draw stripes on the ground ctx.fillStyle = “#d8c174”; for (let i = 0; i < canvas.width; i += 30) { ctx.fillRect(i, canvas.height – groundHeight, 15, 15); } } function drawBird() { ctx.save(); ctx.translate(bird.x + bird.width / 2, bird.y + bird.height / 2); ctx.rotate(bird.rotation); // Bird body ctx.fillStyle = birdColors.body; ctx.beginPath(); ctx.ellipse(0, 0, bird.width / 2, bird.height / 2, 0, 0, Math.PI * 2); ctx.fill(); // Wing ctx.fillStyle = birdColors.wing; ctx.beginPath(); ctx.ellipse(-5, 0, 8, 6, Math.PI / 4, 0, Math.PI * 2); ctx.fill(); // Eye ctx.fillStyle = birdColors.eye; ctx.beginPath(); ctx.arc(8, -5, 3, 0, Math.PI * 2); ctx.fill(); // Beak ctx.fillStyle = birdColors.beak; ctx.beginPath(); ctx.moveTo(14, -2); ctx.lineTo(20, 0); ctx.lineTo(14, 2); ctx.closePath(); ctx.fill(); ctx.restore(); } function drawPipes() { pipes.forEach(pipe => { // Top pipe ctx.fillStyle = pipeColor; ctx.fillRect(pipe.x, 0, pipeWidth, pipe.topHeight); // Top pipe border ctx.fillStyle = pipeBorderColor; ctx.fillRect(pipe.x – 2, pipe.topHeight – 15, pipeWidth + 4, 15); // Bottom pipe ctx.fillStyle = pipeColor; ctx.fillRect(pipe.x, pipe.topHeight + pipeGap, pipeWidth, canvas.height – (pipe.topHeight + pipeGap) – groundHeight); // Bottom pipe border ctx.fillStyle = pipeBorderColor; ctx.fillRect(pipe.x – 2, pipe.topHeight + pipeGap, pipeWidth + 4, 15); }); } function drawScore() { ctx.fillStyle = “#ffffff”; ctx.strokeStyle = “#000000”; ctx.lineWidth = 2; ctx.font = “bold 30px Arial”; ctx.textAlign = “center”; ctx.fillText(score, canvas.width / 2, 50); ctx.strokeText(score, canvas.width / 2, 50); } function createPipe() { const topHeight = Math.floor(Math.random() * (canvas.height – groundHeight – pipeGap – 100)) + 50; pipes.push({ x: canvas.width, topHeight: topHeight, passed: false }); } // Update functions function updateBird() { // Apply gravity to velocity bird.velocity += bird.gravity; // Update position based on velocity bird.y += bird.velocity; // Update rotation based on velocity if (bird.velocity < 0) { bird.rotation = -Math.PI / 6; // Point upward when jumping } else { // Point downward, but limit the rotation bird.rotation = Math.min(Math.PI / 2, Math.PI / 6 + (bird.velocity * 0.1)); } // Ground collision if (bird.y + bird.height > canvas.height – groundHeight) { bird.y = canvas.height – groundHeight – bird.height; endGame(); } // Ceiling collision if (bird.y < 0) { bird.y = 0; bird.velocity = 0; } } function updatePipes(deltaTime) { // Add new pipe if it’s time if (gameRunning && lastPipeTime > pipeInterval) { createPipe(); lastPipeTime = 0; } else { lastPipeTime += deltaTime; } // Move pipes left pipes.forEach(pipe => { pipe.x -= 3; // Check for passing pipe (score point) if (!pipe.passed && pipe.x + pipeWidth < bird.x) { pipe.passed = true; score++; playSound(‘point’); } // Check for collision if ( bird.x + bird.width – 5 > pipe.x && bird.x + 5 < pipe.x + pipeWidth && ( bird.y + 5 < pipe.topHeight || bird.y + bird.height – 5 > pipe.topHeight + pipeGap ) ) { endGame(); } }); // Remove pipes that have gone off screen pipes = pipes.filter(pipe => pipe.x + pipeWidth > 0); } // Game loop function gameLoop(timestamp) { const deltaTime = timestamp – lastTimestamp; lastTimestamp = timestamp; // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw background drawSky(); drawPipes(); drawGround(); // Update game state if running if (gameRunning && !gameOver) { updateBird(); updatePipes(deltaTime); } // Draw bird drawBird(); // Draw score drawScore(); // Continue animation if (!gameOver) { animationFrameId = requestAnimationFrame(gameLoop); } } // Game controls function jump() { if (gameRunning && !gameOver) { bird.velocity = bird.jump; playSound(‘wing’); } } function startGame() { gameRunning = true; gameOver = false; score = 0; bird.y = canvas.height / 2 – 10; bird.velocity = 0; bird.rotation = 0; pipes = []; lastPipeTime = 0; startScreen.classList.add(‘hidden’); gameOverScreen.classList.add(‘hidden’); lastTimestamp = performance.now(); animationFrameId = requestAnimationFrame(gameLoop); } function endGame() { if (gameOver) return; gameRunning = false; gameOver = true; // Update best score if (score > bestScore) { bestScore = score; localStorage.setItem(‘flappyBirdBestScore’, bestScore); } finalScoreElement.textContent = score; bestScoreElement.textContent = bestScore; gameOverScreen.classList.remove(‘hidden’); playSound(‘hit’); } // Sound effects (optional feature, using audio contexts for more reliable mobile playback) const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const sounds = { wing: { frequency: 600, duration: 0.1, type: ‘square’ }, hit: { frequency: 300, duration: 0.3, type: ‘triangle’ }, point: { frequency: 800, duration: 0.1, type: ‘sine’ } }; function playSound(name) { if (!sounds[name]) return; const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.type = sounds[name].type; oscillator.frequency.value = sounds[name].frequency; oscillator.connect(gainNode); gainNode.connect(audioContext.destination); gainNode.gain.value = 0.2; oscillator.start(audioContext.currentTime); gainNode.gain.exponentialRampToValueAtTime( 0.00001, audioContext.currentTime + sounds[name].duration ); setTimeout(() => { oscillator.stop(); }, sounds[name].duration * 1000); } // Event listeners canvas.addEventListener(‘click’, () => { if (!gameRunning && !gameOver) { startGame(); } else { jump(); } }); document.addEventListener(‘keydown’, (event) => { if (event.code === ‘Space’) { event.preventDefault(); if (!gameRunning && !gameOver) { startGame(); } else { jump(); } } }); startButton.addEventListener(‘click’, startGame); restartButton.addEventListener(‘click’, startGame); // Initialize the first frame drawSky(); drawGround(); drawBird(); }); </script> </body> </html>