|
| 1 | +let paused = false; |
| 2 | +const canvas = document.getElementById('gameCanvas'); |
| 3 | +const ctx = canvas.getContext('2d'); |
| 4 | + |
| 5 | +// Load images |
| 6 | +const bgImage = new Image(); |
| 7 | +bgImage.src = 'background.jpg'; |
| 8 | + |
| 9 | +const playerImage = new Image(); |
| 10 | +playerImage.src = 'player.png'; |
| 11 | + |
| 12 | +const enemyImage = new Image(); |
| 13 | +enemyImage.src = 'enemy.png'; |
| 14 | + |
| 15 | +// Resize canvas |
| 16 | +function resizeCanvas() { |
| 17 | + canvas.width = window.innerWidth; |
| 18 | + canvas.height = window.innerHeight; |
| 19 | +} |
| 20 | +resizeCanvas(); |
| 21 | +window.addEventListener('resize', resizeCanvas); |
| 22 | + |
| 23 | +// Load sounds |
| 24 | +const bgMusic = document.getElementById('bg-music'); |
| 25 | +const hitSound = document.getElementById('hit-sound'); |
| 26 | +const spawnSound = document.getElementById('spawn-sound'); |
| 27 | + |
| 28 | +// Game objects |
| 29 | +const player = { |
| 30 | + x: canvas.width / 2 - 20, |
| 31 | + y: canvas.height - 60, |
| 32 | + width: 40, |
| 33 | + height: 40, |
| 34 | + speed: 5, |
| 35 | + moveLeft: false, |
| 36 | + moveRight: false, |
| 37 | + bullets: [] |
| 38 | +}; |
| 39 | + |
| 40 | +let enemies = []; |
| 41 | +let score = 0; |
| 42 | +let lives = 3; |
| 43 | +let gameOver = false; |
| 44 | +let started = false; |
| 45 | + |
| 46 | +// Draw functions |
| 47 | +function drawBackground() { |
| 48 | + ctx.drawImage(bgImage, 0, 0, canvas.width, canvas.height); |
| 49 | +} |
| 50 | + |
| 51 | +function drawPlayer() { |
| 52 | + ctx.drawImage(playerImage, player.x, player.y, player.width, player.height); |
| 53 | +} |
| 54 | + |
| 55 | +function drawEnemies() { |
| 56 | + enemies.forEach(e => ctx.drawImage(enemyImage, e.x, e.y, e.width, e.height)); |
| 57 | +} |
| 58 | + |
| 59 | +function drawBullets() { |
| 60 | + ctx.fillStyle = 'yellow'; |
| 61 | + player.bullets.forEach(b => ctx.fillRect(b.x, b.y, 4, 10)); |
| 62 | +} |
| 63 | + |
| 64 | +function drawUI() { |
| 65 | + ctx.fillStyle = 'white'; |
| 66 | + ctx.font = '20px Arial'; |
| 67 | + ctx.fillText(`Score: ${score}`, 10, 30); |
| 68 | + ctx.fillText(`Lives: ${lives}`, canvas.width - 100, 30); |
| 69 | +} |
| 70 | + |
| 71 | +function drawGameOver() { |
| 72 | + ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; |
| 73 | + ctx.fillRect(0, 0, canvas.width, canvas.height); |
| 74 | + ctx.fillStyle = 'white'; |
| 75 | + ctx.font = '36px Arial'; |
| 76 | + ctx.fillText('Game Over', canvas.width / 2 - 100, canvas.height / 2 - 20); |
| 77 | + ctx.font = '24px Arial'; |
| 78 | + ctx.fillText(`Score: ${score}`, canvas.width / 2 - 40, canvas.height / 2 + 20); |
| 79 | + ctx.fillText('Press R to Restart', canvas.width / 2 - 90, canvas.height / 2 + 60); |
| 80 | +} |
| 81 | + |
| 82 | +function drawStartScreen() { |
| 83 | + ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; |
| 84 | + ctx.fillRect(0, 0, canvas.width, canvas.height); |
| 85 | + ctx.fillStyle = 'white'; |
| 86 | + ctx.font = '28px Arial'; |
| 87 | + ctx.fillText('Dodge & Survive', canvas.width / 2 - 100, canvas.height / 2 - 30); |
| 88 | + ctx.font = '20px Arial'; |
| 89 | + ctx.fillText('Press Enter or Click to Start', canvas.width / 2 - 110, canvas.height / 2 + 10); |
| 90 | +} |
| 91 | + |
| 92 | +// Game logic |
| 93 | +function updateEnemies() { |
| 94 | + enemies.forEach(e => e.y += 2); |
| 95 | + enemies = enemies.filter(e => e.y < canvas.height); |
| 96 | +} |
| 97 | + |
| 98 | +function updateBullets() { |
| 99 | + player.bullets.forEach(b => b.y -= 8); |
| 100 | + player.bullets = player.bullets.filter(b => b.y > 0); |
| 101 | +} |
| 102 | + |
| 103 | +function checkCollision(a, b) { |
| 104 | + return ( |
| 105 | + a.x < b.x + b.width && |
| 106 | + a.x + (a.width || 4) > b.x && |
| 107 | + a.y < b.y + b.height && |
| 108 | + a.y + (a.height || 10) > b.y |
| 109 | + ); |
| 110 | +} |
| 111 | + |
| 112 | +function handleCollisions() { |
| 113 | + // Bullet hits enemy |
| 114 | + for (let i = enemies.length - 1; i >= 0; i--) { |
| 115 | + for (let j = player.bullets.length - 1; j >= 0; j--) { |
| 116 | + if (checkCollision(player.bullets[j], enemies[i])) { |
| 117 | + enemies.splice(i, 1); |
| 118 | + player.bullets.splice(j, 1); |
| 119 | + score += 1; |
| 120 | + hitSound.currentTime = 0; |
| 121 | + hitSound.play(); |
| 122 | + break; |
| 123 | + } |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + // Enemy hits player |
| 128 | + for (let i = enemies.length - 1; i >= 0; i--) { |
| 129 | + if (checkCollision(enemies[i], player)) { |
| 130 | + enemies.splice(i, 1); |
| 131 | + lives -= 1; |
| 132 | + hitSound.currentTime = 0; |
| 133 | + hitSound.play(); |
| 134 | + if (lives <= 0) { |
| 135 | + gameOver = true; |
| 136 | + bgMusic.pause(); |
| 137 | + bgMusic.currentTime = 0; |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | +} |
| 142 | + |
| 143 | +function shoot() { |
| 144 | + player.bullets.push({ |
| 145 | + x: player.x + player.width / 2 - 2, |
| 146 | + y: player.y, |
| 147 | + }); |
| 148 | +} |
| 149 | + |
| 150 | +function createEnemy() { |
| 151 | + const x = Math.random() * (canvas.width - 40); |
| 152 | + enemies.push({ x, y: -40, width: 40, height: 40 }); |
| 153 | + spawnSound.currentTime = 0; |
| 154 | + spawnSound.play(); |
| 155 | +} |
| 156 | + |
| 157 | +function resetGame() { |
| 158 | + enemies = []; |
| 159 | + player.bullets = []; |
| 160 | + score = 0; |
| 161 | + lives = 3; |
| 162 | + gameOver = false; |
| 163 | + player.x = canvas.width / 2 - 20; |
| 164 | + bgMusic.currentTime = 0; |
| 165 | + bgMusic.play(); |
| 166 | +} |
| 167 | + |
| 168 | +// Game loop |
| 169 | +function gameLoop() { |
| 170 | + drawBackground(); |
| 171 | + |
| 172 | + if (!started) { |
| 173 | + drawStartScreen(); |
| 174 | + requestAnimationFrame(gameLoop); |
| 175 | + return; |
| 176 | + } |
| 177 | + |
| 178 | + if (!gameOver) { |
| 179 | + if (player.moveLeft && player.x > 0) player.x -= player.speed; |
| 180 | + if (player.moveRight && player.x + player.width < canvas.width) |
| 181 | + player.x += player.speed; |
| 182 | + |
| 183 | + updateEnemies(); |
| 184 | + updateBullets(); |
| 185 | + handleCollisions(); |
| 186 | + |
| 187 | + drawPlayer(); |
| 188 | + drawEnemies(); |
| 189 | + drawBullets(); |
| 190 | + drawUI(); |
| 191 | + } else { |
| 192 | + drawGameOver(); |
| 193 | + } |
| 194 | + |
| 195 | + requestAnimationFrame(gameLoop); |
| 196 | +} |
| 197 | + |
| 198 | +// Controls |
| 199 | +document.addEventListener('keydown', (e) => { |
| 200 | + if (e.key === 'ArrowLeft' || e.key === 'a') player.moveLeft = true; |
| 201 | + if (e.key === 'ArrowRight' || e.key === 'd') player.moveRight = true; |
| 202 | + if (e.key === ' ' && started && !gameOver) shoot(); |
| 203 | + if ((e.key === 'Enter' || e.key === ' ') && !started) { |
| 204 | + started = true; |
| 205 | + bgMusic.play(); |
| 206 | + } |
| 207 | + if (e.key === 'r' && gameOver) resetGame(); |
| 208 | +}); |
| 209 | + |
| 210 | +document.addEventListener('keyup', (e) => { |
| 211 | + if (e.key === 'ArrowLeft' || e.key === 'a') player.moveLeft = false; |
| 212 | + if (e.key === 'ArrowRight' || e.key === 'd') player.moveRight = false; |
| 213 | +}); |
| 214 | + |
| 215 | +canvas.addEventListener('click', () => { |
| 216 | + if (!started) { |
| 217 | + started = true; |
| 218 | + bgMusic.play(); |
| 219 | + } |
| 220 | +}); |
| 221 | + |
| 222 | +// Start enemy spawning |
| 223 | +setInterval(() => { |
| 224 | + if (started && !gameOver) createEnemy(); |
| 225 | +}, 1000); |
| 226 | + |
| 227 | +window.onload = gameLoop; |
0 commit comments