document.addEventListener('DOMContentLoaded', () => { const canvas = document.getElementById('gameCanvas'); if (!canvas) { console.error('Canvas element not found!'); return; } const ctx = canvas.getContext('2d'); // Set fixed canvas size canvas.width = 800; canvas.height = 600; const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); let score = 0; let lives = 3; let gameOver = false; let gameStarted = false; let orangeInterval; const player = { width: 100, height: 50, x: canvas.width / 2 - 50, y: canvas.height - 60, speed: 500, dx: 0, draw() { ctx.fillStyle = '#8B4513'; ctx.beginPath(); ctx.moveTo(this.x, this.y); ctx.lineTo(this.x + this.width, this.y); ctx.lineTo(this.x + this.width - 15, this.y + this.height); ctx.lineTo(this.x + 15, this.y + this.height); ctx.closePath(); ctx.fill(); ctx.strokeStyle = '#5C2F0E'; ctx.lineWidth = 8; ctx.beginPath(); ctx.moveTo(this.x, this.y); ctx.lineTo(this.x + this.width, this.y); ctx.stroke(); } }; const orangeProps = { size: 20, speed: 150, }; let oranges = []; function createOrange() { oranges.push({ x: Math.random() * (canvas.width - orangeProps.size), y: -orangeProps.size, size: orangeProps.size, speed: orangeProps.speed + Math.random() * 100, draw() { ctx.beginPath(); ctx.arc(this.x + this.size / 2, this.y + this.size / 2, this.size, 0, Math.PI * 2); ctx.fillStyle = '#FFA500'; ctx.fill(); ctx.beginPath(); ctx.ellipse(this.x + this.size / 2 + 5, this.y, 8, 3, Math.PI / 4, 0, Math.PI * 2); ctx.fillStyle = '#228B22'; ctx.fill(); } }); } let lastTime = 0; function update(timestamp) { if (!gameStarted) return; if (gameOver) { drawGameOver(); return; } const deltaTime = (timestamp - lastTime) / 1000; lastTime = timestamp; ctx.clearRect(0, 0, canvas.width, canvas.height); drawScene(); player.draw(); player.x += player.dx * player.speed * deltaTime; if (player.x < 0) player.x = 0; if (player.x + player.width > canvas.width) { player.x = canvas.width - player.width; } oranges.forEach((orange, index) => { orange.y += orange.speed * deltaTime; orange.draw(); if ( orange.y + orange.size > player.y && orange.x < player.x + player.width && orange.x + orange.size > player.x ) { score++; playCatchSound(); oranges.splice(index, 1); } if (orange.y > canvas.height) { lives--; oranges.splice(index, 1); if (lives <= 0) { gameOver = true; } } }); drawUI(); requestAnimationFrame(update); } function drawScene() { ctx.fillStyle = '#0A192F'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#228B22'; ctx.fillRect(0, canvas.height - 20, canvas.width, 20); } function drawUI() { ctx.fillStyle = '#E6F1FF'; ctx.font = '24px Poppins, sans-serif'; ctx.textAlign = 'left'; ctx.fillText(`Score: ${score}`, 20, 40); ctx.textAlign = 'right'; ctx.fillText(`Lives: ${lives}`, canvas.width - 20, 40); ctx.textAlign = 'center'; } function drawGameOver() { clearInterval(orangeInterval); ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#E6F1FF'; ctx.font = '50px Poppins, sans-serif'; ctx.textAlign = 'center'; ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2 - 40); ctx.font = '30px Poppins, sans-serif'; ctx.fillText(`Final Score: ${score}`, canvas.width / 2, canvas.height / 2 + 20); ctx.font = '20px Poppins, sans-serif'; ctx.fillText('Click to Restart', canvas.width / 2, canvas.height / 2 + 70); } function drawInitialMessage() { ctx.fillStyle = '#E6F1FF'; ctx.font = '30px Poppins, sans-serif'; ctx.textAlign = 'center'; ctx.fillText('Click "Play Now" to Start!', canvas.width / 2, canvas.height / 2); } function playCatchSound() { if (!audioCtx) return; const oscillator = audioCtx.createOscillator(); const gainNode = audioCtx.createGain(); oscillator.connect(gainNode); gainNode.connect(audioCtx.destination); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(880, audioCtx.currentTime); gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 0.5); oscillator.start(audioCtx.currentTime); oscillator.stop(audioCtx.currentTime + 0.5); } async function updateLeaderboard() { try { const response = await fetch('/api/scores/'); const scores = await response.json(); const leaderboardBody = document.getElementById('leaderboard-body'); leaderboardBody.innerHTML = ''; scores.forEach((score, index) => { const row = `