|
8 | 8 | margin: 0; |
9 | 9 | overflow: hidden; |
10 | 10 | background-color: #333; |
| 11 | + font-family: Arial, sans-serif; |
11 | 12 | } |
12 | 13 | #gameCanvas { |
13 | 14 | display: block; |
|
22 | 23 | border: 2px solid white; |
23 | 24 | background-color: rgba(0, 0, 0, 0.5); |
24 | 25 | } |
25 | | - #lives { |
| 26 | + #gameInfo { |
26 | 27 | position: absolute; |
27 | 28 | top: 170px; |
28 | 29 | left: 10px; |
29 | 30 | color: white; |
30 | | - font-family: Arial; |
31 | 31 | font-size: 16px; |
32 | 32 | } |
33 | 33 | </style> |
34 | 34 | </head> |
35 | 35 | <body> |
36 | 36 | <canvas id="gameCanvas"></canvas> |
37 | 37 | <canvas id="miniMap"></canvas> |
38 | | - <div id="lives">Lives: 3</div> |
| 38 | + <div id="gameInfo"> |
| 39 | + <div id="lives">Lives: 3</div> |
| 40 | + <div id="score">Score: 0</div> |
| 41 | + </div> |
39 | 42 |
|
40 | 43 | <script> |
41 | 44 | // 游戏主画布 |
|
51 | 54 | // 游戏状态 |
52 | 55 | let gameRunning = true; |
53 | 56 | let playerLives = 3; |
| 57 | + let score = 0; |
54 | 58 | const livesDisplay = document.getElementById('lives'); |
| 59 | + const scoreDisplay = document.getElementById('score'); |
55 | 60 |
|
56 | 61 | // 玩家坦克 |
57 | 62 | const playerTank = { |
|
61 | 66 | height: 30, |
62 | 67 | color: 'blue', |
63 | 68 | speed: 3, |
64 | | - direction: 0, // 0: up, 1: right, 2: down, 3: left |
| 69 | + direction: 0, |
65 | 70 | bullets: [], |
66 | 71 | lastShot: 0, |
67 | 72 | shootDelay: 500, |
68 | 73 | isPlayer: true |
69 | 74 | }; |
70 | 75 |
|
71 | | - // 我方AI坦克 |
| 76 | + // 我方AI坦克(修复了显示问题) |
72 | 77 | const allyTank = { |
73 | 78 | x: 200, |
74 | 79 | y: 200, |
|
83 | 88 | isPlayer: false, |
84 | 89 | isAlly: true, |
85 | 90 | aiTimer: 0, |
86 | | - aiInterval: 2000 |
| 91 | + aiInterval: 2000, |
| 92 | + alive: true // 添加了alive状态 |
87 | 93 | }; |
88 | 94 |
|
89 | 95 | // 敌方AI坦克 |
90 | | - const enemyTank = { |
| 96 | + let enemyTank = { |
91 | 97 | x: 600, |
92 | 98 | y: 400, |
93 | 99 | width: 30, |
|
101 | 107 | isPlayer: false, |
102 | 108 | isAlly: false, |
103 | 109 | aiTimer: 0, |
104 | | - aiInterval: 3000 |
| 110 | + aiInterval: 3000, |
| 111 | + alive: true, |
| 112 | + respawnTimer: 0 |
105 | 113 | }; |
106 | 114 |
|
107 | 115 | // 障碍物 |
|
151 | 159 |
|
152 | 160 | // 我方AI行为 |
153 | 161 | function allyAI(tank, deltaTime) { |
| 162 | + if (!tank.alive) return; |
| 163 | + |
154 | 164 | tank.aiTimer += deltaTime; |
155 | 165 | if (tank.aiTimer >= tank.aiInterval) { |
156 | 166 | tank.aiTimer = 0; |
157 | 167 | tank.direction = Math.floor(Math.random() * 4); |
158 | 168 |
|
159 | | - // 有概率射击 |
160 | 169 | if (Math.random() < 0.7) { |
161 | 170 | shoot(tank); |
162 | 171 | } |
163 | 172 | } |
164 | 173 |
|
165 | | - // 简单移动 |
166 | 174 | moveTank(tank); |
167 | | - |
168 | | - // 避免障碍物 |
169 | 175 | avoidObstacles(tank); |
170 | 176 | } |
171 | 177 |
|
172 | 178 | // 敌方AI行为 |
173 | 179 | function enemyAI(tank, deltaTime) { |
| 180 | + if (!tank.alive) { |
| 181 | + tank.respawnTimer += deltaTime; |
| 182 | + if (tank.respawnTimer >= 3000) { |
| 183 | + respawnEnemy(); |
| 184 | + } |
| 185 | + return; |
| 186 | + } |
| 187 | + |
174 | 188 | tank.aiTimer += deltaTime; |
175 | 189 | if (tank.aiTimer >= tank.aiInterval) { |
176 | 190 | tank.aiTimer = 0; |
177 | 191 |
|
178 | | - // 朝向玩家 |
179 | 192 | const dx = playerTank.x - tank.x; |
180 | 193 | const dy = playerTank.y - tank.y; |
181 | 194 |
|
|
185 | 198 | tank.direction = dy > 0 ? 2 : 0; |
186 | 199 | } |
187 | 200 |
|
188 | | - // 高概率射击 |
189 | 201 | if (Math.random() < 0.8) { |
190 | 202 | shoot(tank); |
191 | 203 | } |
192 | 204 | } |
193 | 205 |
|
194 | | - // 简单移动 |
195 | 206 | moveTank(tank); |
196 | | - |
197 | | - // 避免障碍物 |
198 | 207 | avoidObstacles(tank); |
199 | 208 | } |
200 | 209 |
|
| 210 | + // 重生敌方坦克 |
| 211 | + function respawnEnemy() { |
| 212 | + enemyTank = { |
| 213 | + x: Math.random() > 0.5 ? 100 : 700, |
| 214 | + y: Math.random() > 0.5 ? 100 : 500, |
| 215 | + width: 30, |
| 216 | + height: 30, |
| 217 | + color: 'red', |
| 218 | + speed: 2, |
| 219 | + direction: Math.floor(Math.random() * 4), |
| 220 | + bullets: [], |
| 221 | + lastShot: 0, |
| 222 | + shootDelay: 1500, |
| 223 | + isPlayer: false, |
| 224 | + isAlly: false, |
| 225 | + aiTimer: 0, |
| 226 | + aiInterval: 3000, |
| 227 | + alive: true, |
| 228 | + respawnTimer: 0 |
| 229 | + }; |
| 230 | + } |
| 231 | + |
201 | 232 | // 移动坦克 |
202 | 233 | function moveTank(tank) { |
| 234 | + if (!tank.alive) return; |
| 235 | + |
203 | 236 | let newX = tank.x; |
204 | 237 | let newY = tank.y; |
205 | 238 |
|
206 | 239 | switch(tank.direction) { |
207 | | - case 0: newY -= tank.speed; break; // up |
208 | | - case 1: newX += tank.speed; break; // right |
209 | | - case 2: newY += tank.speed; break; // down |
210 | | - case 3: newX -= tank.speed; break; // left |
| 240 | + case 0: newY -= tank.speed; break; |
| 241 | + case 1: newX += tank.speed; break; |
| 242 | + case 2: newY += tank.speed; break; |
| 243 | + case 3: newX -= tank.speed; break; |
211 | 244 | } |
212 | 245 |
|
213 | | - // 边界检查 |
214 | 246 | if (newX >= 0 && newX + tank.width <= canvas.width) { |
215 | 247 | tank.x = newX; |
216 | 248 | } |
|
221 | 253 |
|
222 | 254 | // 避免障碍物 |
223 | 255 | function avoidObstacles(tank) { |
| 256 | + if (!tank.alive) return; |
| 257 | + |
224 | 258 | for (const obstacle of obstacles) { |
225 | 259 | if (checkCollision(tank, obstacle)) { |
226 | | - // 后退并改变方向 |
227 | 260 | switch(tank.direction) { |
228 | 261 | case 0: tank.y += tank.speed; break; |
229 | 262 | case 1: tank.x -= tank.speed; break; |
|
249 | 282 | for (let i = tank.bullets.length - 1; i >= 0; i--) { |
250 | 283 | const bullet = tank.bullets[i]; |
251 | 284 |
|
252 | | - // 移动子弹 |
253 | 285 | switch(bullet.direction) { |
254 | 286 | case 0: bullet.y -= bullet.speed; break; |
255 | 287 | case 1: bullet.x += bullet.speed; break; |
256 | 288 | case 2: bullet.y += bullet.speed; break; |
257 | 289 | case 3: bullet.x -= bullet.speed; break; |
258 | 290 | } |
259 | 291 |
|
260 | | - // 边界检查 |
261 | 292 | if (bullet.x < 0 || bullet.x > canvas.width || |
262 | 293 | bullet.y < 0 || bullet.y > canvas.height) { |
263 | 294 | tank.bullets.splice(i, 1); |
264 | 295 | continue; |
265 | 296 | } |
266 | 297 |
|
267 | | - // 障碍物碰撞 |
268 | 298 | for (const obstacle of obstacles) { |
269 | 299 | if (checkCollision(bullet, obstacle)) { |
270 | 300 | tank.bullets.splice(i, 1); |
271 | 301 | break; |
272 | 302 | } |
273 | 303 | } |
274 | 304 |
|
275 | | - // 坦克碰撞 |
276 | 305 | if (bullet.owner !== playerTank && checkCollision(bullet, playerTank)) { |
277 | 306 | tank.bullets.splice(i, 1); |
278 | 307 | playerHit(); |
|
281 | 310 |
|
282 | 311 | if (bullet.owner !== allyTank && bullet.owner !== playerTank && checkCollision(bullet, allyTank)) { |
283 | 312 | tank.bullets.splice(i, 1); |
284 | | - // 盟友被击中逻辑可以在这里添加 |
285 | 313 | continue; |
286 | 314 | } |
287 | 315 |
|
288 | | - if (bullet.owner !== enemyTank && bullet.owner !== playerTank && checkCollision(bullet, enemyTank)) { |
| 316 | + if (bullet.owner !== enemyTank && checkCollision(bullet, enemyTank) && enemyTank.alive) { |
289 | 317 | tank.bullets.splice(i, 1); |
290 | | - // 敌人被击中逻辑可以在这里添加 |
| 318 | + enemyHit(); |
291 | 319 | continue; |
292 | 320 | } |
293 | 321 | } |
|
296 | 324 | // 玩家被击中 |
297 | 325 | function playerHit() { |
298 | 326 | playerLives--; |
299 | | - livesDisplay.textContent = `等级 ${playerLives}`; |
| 327 | + livesDisplay.textContent = `Lives: ${playerLives}`; |
300 | 328 |
|
301 | 329 | if (playerLives <= 0) { |
302 | 330 | gameOver(); |
303 | 331 | } else { |
304 | | - // 重置玩家位置 |
305 | 332 | playerTank.x = 400; |
306 | 333 | playerTank.y = 300; |
307 | 334 | } |
308 | 335 | } |
309 | 336 |
|
| 337 | + // 敌人被击中 |
| 338 | + function enemyHit() { |
| 339 | + enemyTank.alive = false; |
| 340 | + enemyTank.respawnTimer = 0; |
| 341 | + score += 100; |
| 342 | + scoreDisplay.textContent = `Score: ${score}`; |
| 343 | + } |
| 344 | + |
310 | 345 | // 游戏结束 |
311 | 346 | function gameOver() { |
312 | 347 | gameRunning = false; |
|
316 | 351 | ctx.fillText('GAME OVER', canvas.width/2, canvas.height/2); |
317 | 352 | } |
318 | 353 |
|
319 | | - // 绘制坦克 |
| 354 | + // 绘制坦克(修复了显示问题) |
320 | 355 | function drawTank(tank) { |
| 356 | + if (!tank.alive) return; |
| 357 | + |
321 | 358 | ctx.fillStyle = tank.color; |
322 | 359 | ctx.fillRect(tank.x, tank.y, tank.width, tank.height); |
323 | 360 |
|
|
328 | 365 | let barrelLength = 15; |
329 | 366 |
|
330 | 367 | switch(tank.direction) { |
331 | | - case 0: // up |
332 | | - ctx.fillRect(barrelX - 2.5, barrelY - barrelLength, 5, barrelLength); |
333 | | - break; |
334 | | - case 1: // right |
335 | | - ctx.fillRect(barrelX, barrelY - 2.5, barrelLength, 5); |
336 | | - break; |
337 | | - case 2: // down |
338 | | - ctx.fillRect(barrelX - 2.5, barrelY, 5, barrelLength); |
339 | | - break; |
340 | | - case 3: // left |
341 | | - ctx.fillRect(barrelX - barrelLength, barrelY - 2.5, barrelLength, 5); |
342 | | - break; |
| 368 | + case 0: ctx.fillRect(barrelX - 2.5, barrelY - barrelLength, 5, barrelLength); break; |
| 369 | + case 1: ctx.fillRect(barrelX, barrelY - 2.5, barrelLength, 5); break; |
| 370 | + case 2: ctx.fillRect(barrelX - 2.5, barrelY, 5, barrelLength); break; |
| 371 | + case 3: ctx.fillRect(barrelX - barrelLength, barrelY - 2.5, barrelLength, 5); break; |
343 | 372 | } |
344 | 373 | } |
345 | 374 |
|
|
363 | 392 | function updateMiniMap() { |
364 | 393 | miniMapCtx.clearRect(0, 0, miniMapCanvas.width, miniMapCanvas.height); |
365 | 394 |
|
366 | | - // 计算缩放比例 |
367 | 395 | const scaleX = miniMapCanvas.width / canvas.width; |
368 | 396 | const scaleY = miniMapCanvas.height / canvas.height; |
369 | 397 |
|
370 | | - // 绘制障碍物 |
371 | 398 | miniMapCtx.fillStyle = 'gray'; |
372 | 399 | for (const obstacle of obstacles) { |
373 | 400 | miniMapCtx.fillRect( |
|
378 | 405 | ); |
379 | 406 | } |
380 | 407 |
|
381 | | - // 绘制坦克 |
382 | 408 | miniMapCtx.fillStyle = playerTank.color; |
383 | 409 | miniMapCtx.fillRect( |
384 | 410 | playerTank.x * scaleX, |
|
395 | 421 | allyTank.height * scaleY |
396 | 422 | ); |
397 | 423 |
|
398 | | - miniMapCtx.fillStyle = enemyTank.color; |
399 | | - miniMapCtx.fillRect( |
400 | | - enemyTank.x * scaleX, |
401 | | - enemyTank.y * scaleY, |
402 | | - enemyTank.width * scaleX, |
403 | | - enemyTank.height * scaleY |
404 | | - ); |
| 424 | + if (enemyTank.alive) { |
| 425 | + miniMapCtx.fillStyle = enemyTank.color; |
| 426 | + miniMapCtx.fillRect( |
| 427 | + enemyTank.x * scaleX, |
| 428 | + enemyTank.y * scaleY, |
| 429 | + enemyTank.width * scaleX, |
| 430 | + enemyTank.height * scaleY |
| 431 | + ); |
| 432 | + } |
405 | 433 | } |
406 | 434 |
|
407 | 435 | // 游戏主循环 |
|
412 | 440 | const deltaTime = timestamp - lastTime; |
413 | 441 | lastTime = timestamp; |
414 | 442 |
|
415 | | - // 清空画布 |
416 | 443 | ctx.clearRect(0, 0, canvas.width, canvas.height); |
417 | 444 |
|
418 | 445 | // 玩家控制 |
|
449 | 476 | // 绘制游戏元素 |
450 | 477 | drawObstacles(); |
451 | 478 | drawTank(playerTank); |
452 | | - drawTank(allyTank); |
| 479 | + drawTank(allyTank); // 确保调用绘制我方坦克 |
453 | 480 | drawTank(enemyTank); |
454 | 481 | drawBullets(playerTank); |
455 | 482 | drawBullets(allyTank); |
|
0 commit comments