zdwalter commited on
Commit
76576f9
·
verified ·
1 Parent(s): 1be7e09

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +499 -34
index.html CHANGED
@@ -112,6 +112,39 @@
112
  background-color: #777;
113
  border-radius: 2px;
114
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  </style>
116
  </head>
117
  <body class="bg-gray-900 text-white flex flex-col items-center justify-center h-screen">
@@ -122,27 +155,26 @@
122
  <div id="startScreen" class="game-overlay flex flex-col items-center justify-center bg-black bg-opacity-70">
123
  <h1 class="text-5xl font-bold mb-6 text-yellow-300">SKY ADVENTURE</h1>
124
  <div class="plane text-6xl mb-8">✈️</div>
125
- <p class="text-xl mb-8 text-center max-w-md px-4">控制飞机躲避障碍物<br>收集星星获得高分!<br>按射击按钮消灭障碍物!<br>大型障碍物会分裂!</p>
126
  <button id="startButton" class="bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-3 px-8 rounded-full text-xl transition-all duration-300 transform hover:scale-105 pointer-events-auto">
127
  开始游戏
128
  </button>
129
- <div class="mt-8 flex flex-wrap justify-center gap-4">
130
  <div class="flex items-center">
131
- <i class="fas fa-arrow-up text-xl mr-2"></i>
132
- <span>上升</span>
133
  </div>
134
  <div class="flex items-center">
135
- <i class="fas fa-arrow-down text-xl mr-2"></i>
136
- <span>下降</span>
137
  </div>
138
  <div class="flex items-center">
139
- <i class="fas fa-arrow-left text-xl mr-2"></i>
140
- <i class="fas fa-arrow-right text-xl"></i>
141
- <span class="ml-2">转向</span>
142
  </div>
143
  <div class="flex items-center">
144
- <i class="fas fa-bolt text-xl mr-2 text-yellow-400"></i>
145
- <span>射击</span>
146
  </div>
147
  </div>
148
  </div>
@@ -175,6 +207,11 @@
175
  </div>
176
  </div>
177
 
 
 
 
 
 
178
  <!-- 触摸控制按钮 -->
179
  <div id="leftBtn" class="control-btn hidden">
180
  <i class="fas fa-arrow-left"></i>
@@ -223,7 +260,15 @@
223
  velocity: 0, // 左右方向速度
224
  verticalVelocity: 0, // 上下方向速度
225
  rotation: 0,
226
- lastFireTime: 0
 
 
 
 
 
 
 
 
227
  },
228
  stars: [],
229
  obstacles: [],
@@ -231,9 +276,13 @@
231
  explosions: [],
232
  bullets: [],
233
  debris: [],
 
 
 
234
  lastStarTime: 0,
235
  lastObstacleTime: 0,
236
  lastCloudTime: 0,
 
237
  keys: {
238
  ArrowUp: false,
239
  ArrowDown: false,
@@ -244,6 +293,52 @@
244
  isMobile: false
245
  };
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  // 获取DOM元素
248
  const canvas = document.getElementById('gameCanvas');
249
  const ctx = canvas.getContext('2d');
@@ -257,6 +352,7 @@
257
  const ammoDisplay = document.getElementById('ammoDisplay');
258
  const speedDisplay = document.getElementById('speedDisplay');
259
  const finalScore = document.getElementById('finalScore');
 
260
  const leftBtn = document.getElementById('leftBtn');
261
  const rightBtn = document.getElementById('rightBtn');
262
  const upBtn = document.getElementById('upBtn');
@@ -278,6 +374,57 @@
278
  }
279
  }
280
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  // 初始化游戏
282
  function initGame() {
283
  gameState.isMobile = detectMobile();
@@ -297,7 +444,15 @@
297
  velocity: 0,
298
  verticalVelocity: 0,
299
  rotation: 0,
300
- lastFireTime: 0
 
 
 
 
 
 
 
 
301
  };
302
  gameState.stars = [];
303
  gameState.obstacles = [];
@@ -305,9 +460,13 @@
305
  gameState.explosions = [];
306
  gameState.bullets = [];
307
  gameState.debris = [];
 
 
 
308
  gameState.lastStarTime = 0;
309
  gameState.lastObstacleTime = 0;
310
  gameState.lastCloudTime = 0;
 
311
 
312
  startScreen.classList.add('hidden');
313
  gameOverScreen.classList.add('hidden');
@@ -394,7 +553,62 @@
394
  });
395
  }
396
 
397
- // 创建障碍物碎片
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  function createDebris(obstacle, count = 5) {
399
  for (let i = 0; i < count; i++) {
400
  gameState.debris.push({
@@ -415,8 +629,9 @@
415
  function createBullet() {
416
  if (gameState.ammo <= 0) return false; // 没有弹药了
417
 
418
- const speed = 15;
419
- const size = 8;
 
420
  const x = gameState.plane.x + 30; // 从飞机前端发射
421
  const y = gameState.plane.y;
422
 
@@ -424,9 +639,16 @@
424
  x,
425
  y,
426
  size,
427
- speed
 
428
  });
429
 
 
 
 
 
 
 
430
  // 如果弹药不是无限的,减少弹药
431
  if (gameState.ammo !== Infinity) {
432
  gameState.ammo--;
@@ -448,14 +670,6 @@
448
  });
449
  }
450
 
451
- // 更新UI
452
- function updateUI() {
453
- scoreDisplay.textContent = gameState.score;
454
- livesDisplay.textContent = gameState.lives;
455
- speedDisplay.textContent = Math.floor(gameState.speed);
456
- ammoDisplay.textContent = gameState.ammo === Infinity ? "∞" : gameState.ammo;
457
- }
458
-
459
  // 检测碰撞
460
  function checkCollision(rect1, rect2) {
461
  return (
@@ -505,11 +719,28 @@
505
 
506
  // 处理开火
507
  if ((gameState.keys.Space || gameState.isFiring) &&
508
- timestamp - gameState.plane.lastFireTime > 200) { // 射击冷却时间200ms
509
  createBullet();
510
  gameState.plane.lastFireTime = timestamp;
511
  }
512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  // 更新飞机速度
514
  if (gameState.keys.ArrowUp || gameState.keys.ArrowDown) {
515
  gameState.speed = Math.max(50,
@@ -571,6 +802,17 @@
571
  gameState.lastCloudTime = timestamp;
572
  }
573
 
 
 
 
 
 
 
 
 
 
 
 
574
  // 更新碎片
575
  gameState.debris.forEach(debris => {
576
  debris.x += debris.speedX;
@@ -580,12 +822,118 @@
580
  });
581
  gameState.debris = gameState.debris.filter(debris => debris.opacity > 0);
582
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
  // 更新云朵
584
  gameState.clouds.forEach(cloud => {
585
  cloud.x -= cloud.speed;
586
  });
587
  gameState.clouds = gameState.clouds.filter(cloud => cloud.x + cloud.size > 0);
588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  // 更新子弹
590
  gameState.bullets.forEach(bullet => {
591
  bullet.x += bullet.speed;
@@ -645,13 +993,21 @@
645
  };
646
 
647
  if (checkCollision(planeRect, obstacleRect) && !gameState.gameOver) {
648
- obstacle.hit = true;
649
- gameState.lives--;
650
- updateUI();
651
- createExplosion(gameState.plane.x, gameState.plane.y);
652
-
653
- if (gameState.lives <= 0) {
654
- endGame();
 
 
 
 
 
 
 
 
655
  }
656
  }
657
 
@@ -668,7 +1024,7 @@
668
  };
669
 
670
  if (checkCollision(bulletRect, obstacleRect)) {
671
- obstacle.health--;
672
  bulletHits.push(bulletIndex);
673
  createExplosion(bullet.x, bullet.y);
674
 
@@ -758,6 +1114,70 @@
758
  ctx.restore();
759
  });
760
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
  // 绘制子弹
762
  gameState.bullets.forEach(bullet => {
763
  const gradient = ctx.createRadialGradient(
@@ -922,6 +1342,22 @@
922
  ctx.translate(gameState.plane.x, gameState.plane.y);
923
  ctx.rotate(gameState.plane.rotation * Math.PI / 180);
924
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
925
  // 飞机主体
926
  ctx.beginPath();
927
  ctx.moveTo(30, 0);
@@ -999,6 +1435,24 @@
999
  ctx.restore();
1000
  });
1001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1002
  // 绘制速度线
1003
  if (gameState.speed > 120) {
1004
  for (let i = 0; i < 10; i++) {
@@ -1034,6 +1488,17 @@
1034
  }
1035
  }
1036
 
 
 
 
 
 
 
 
 
 
 
 
1037
  // 事件监听
1038
  window.addEventListener('resize', resizeCanvas);
1039
 
 
112
  background-color: #777;
113
  border-radius: 2px;
114
  }
115
+ .powerup {
116
+ position: absolute;
117
+ width: 40px;
118
+ height: 40px;
119
+ border-radius: 50%;
120
+ display: flex;
121
+ align-items: center;
122
+ justify-content: center;
123
+ font-size: 20px;
124
+ text-shadow: 0 0 5px white;
125
+ }
126
+ .shield {
127
+ position: absolute;
128
+ border-radius: 50%;
129
+ border: 3px solid rgba(0, 204, 255, 0.6);
130
+ pointer-events: none;
131
+ }
132
+ .homing-missile {
133
+ position: absolute;
134
+ background: linear-gradient(to bottom, #ff5f5f, #ff0000);
135
+ border-radius: 50% 50% 0 0;
136
+ transform-origin: center bottom;
137
+ }
138
+ @keyframes pulse {
139
+ 0% { transform: scale(1); opacity: 0.9; }
140
+ 50% { transform: scale(1.1); opacity: 1; }
141
+ 100% { transform: scale(1); opacity: 0.9; }
142
+ }
143
+ .powerup-effect {
144
+ position: absolute;
145
+ pointer-events: none;
146
+ animation: pulse 1.5s infinite;
147
+ }
148
  </style>
149
  </head>
150
  <body class="bg-gray-900 text-white flex flex-col items-center justify-center h-screen">
 
155
  <div id="startScreen" class="game-overlay flex flex-col items-center justify-center bg-black bg-opacity-70">
156
  <h1 class="text-5xl font-bold mb-6 text-yellow-300">SKY ADVENTURE</h1>
157
  <div class="plane text-6xl mb-8">✈️</div>
158
+ <p class="text-xl mb-8 text-center max-w-md px-4">控制飞机躲避障碍物<br>收集星星获得高分!<br>按射击按钮消灭障碍物!<br>收集道具获得特殊能力!</p>
159
  <button id="startButton" class="bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-3 px-8 rounded-full text-xl transition-all duration-300 transform hover:scale-105 pointer-events-auto">
160
  开始游戏
161
  </button>
162
+ <div class="mt-8 grid grid-cols-2 gap-4 text-left max-w-md px-8">
163
  <div class="flex items-center">
164
+ <div class="powerup bg-red-500 mr-2"><i class="fas fa-bolt"></i></div>
165
+ <span>火力增强</span>
166
  </div>
167
  <div class="flex items-center">
168
+ <div class="powerup bg-purple-500 mr-2"><i class="fas fa-rocket"></i></div>
169
+ <span>跟踪导弹</span>
170
  </div>
171
  <div class="flex items-center">
172
+ <div class="powerup bg-blue-500 mr-2"><i class="fas fa-shield-alt"></i></div>
173
+ <span>保护罩</span>
 
174
  </div>
175
  <div class="flex items-center">
176
+ <div class="powerup bg-green-500 mr-2"><i class="fas fa-heart"></i></div>
177
+ <span>恢复生命</span>
178
  </div>
179
  </div>
180
  </div>
 
207
  </div>
208
  </div>
209
 
210
+ <!-- 主动技能图标 -->
211
+ <div id="powerupStatus" class="absolute bottom-24 right-4 flex gap-2">
212
+ <!-- 这里会被JavaScript动态填充 -->
213
+ </div>
214
+
215
  <!-- 触摸控制按钮 -->
216
  <div id="leftBtn" class="control-btn hidden">
217
  <i class="fas fa-arrow-left"></i>
 
260
  velocity: 0, // 左右方向速度
261
  verticalVelocity: 0, // 上下方向速度
262
  rotation: 0,
263
+ lastFireTime: 0,
264
+ fireRate: 200, // 射击间隔(ms)
265
+ bulletDamage: 1, // 子弹伤害
266
+ hasShield: false,
267
+ shieldDuration: 0,
268
+ powerups: {
269
+ rapidFire: 0, // 火力增强
270
+ homingMissiles: 0, // 跟踪导弹
271
+ }
272
  },
273
  stars: [],
274
  obstacles: [],
 
276
  explosions: [],
277
  bullets: [],
278
  debris: [],
279
+ powerups: [], // 新增: 道具
280
+ homingMissiles: [], // 新增: 跟踪导弹
281
+ effects: [], // 新��: 特效
282
  lastStarTime: 0,
283
  lastObstacleTime: 0,
284
  lastCloudTime: 0,
285
+ lastPowerupTime: 0, // 新增: 上次生成道具时间
286
  keys: {
287
  ArrowUp: false,
288
  ArrowDown: false,
 
293
  isMobile: false
294
  };
295
 
296
+ // 道具类型
297
+ const POWERUP_TYPES = {
298
+ RAPID_FIRE: {
299
+ id: 'rapidFire',
300
+ icon: 'fas fa-bolt',
301
+ color: 'red',
302
+ duration: 10000, // 10秒
303
+ effect: (game) => {
304
+ game.plane.fireRate = 100; // 更快射击
305
+ game.plane.powerups.rapidFire = Date.now() + POWERUP_TYPES.RAPID_FIRE.duration;
306
+ createEffect('火力增强!', 'red', 1500);
307
+ }
308
+ },
309
+ HOMING_MISSILE: {
310
+ id: 'homingMissiles',
311
+ icon: 'fas fa-rocket',
312
+ color: 'purple',
313
+ duration: 10000, // 10秒
314
+ effect: (game) => {
315
+ game.plane.powerups.homingMissiles = Date.now() + POWERUP_TYPES.HOMING_MISSILE.duration;
316
+ createEffect('跟踪导弹已激活!', 'purple', 1500);
317
+ }
318
+ },
319
+ SHIELD: {
320
+ id: 'shield',
321
+ icon: 'fas fa-shield-alt',
322
+ color: 'blue',
323
+ duration: 8000, // 8秒
324
+ effect: (game) => {
325
+ game.plane.hasShield = true;
326
+ game.plane.shieldDuration = Date.now() + POWERUP_TYPES.SHIELD.duration;
327
+ createEffect('保护罩已启用!', 'blue', 1500);
328
+ }
329
+ },
330
+ HEALTH: {
331
+ id: 'health',
332
+ icon: 'fas fa-heart',
333
+ color: 'green',
334
+ effect: (game) => {
335
+ game.lives = Math.min(game.lives + 1, 5); // 最多5条命
336
+ updateUI();
337
+ createEffect('生命值恢复!', 'green', 1500);
338
+ }
339
+ }
340
+ };
341
+
342
  // 获取DOM元素
343
  const canvas = document.getElementById('gameCanvas');
344
  const ctx = canvas.getContext('2d');
 
352
  const ammoDisplay = document.getElementById('ammoDisplay');
353
  const speedDisplay = document.getElementById('speedDisplay');
354
  const finalScore = document.getElementById('finalScore');
355
+ const powerupStatus = document.getElementById('powerupStatus');
356
  const leftBtn = document.getElementById('leftBtn');
357
  const rightBtn = document.getElementById('rightBtn');
358
  const upBtn = document.getElementById('upBtn');
 
374
  }
375
  }
376
 
377
+ // 创建文字特效
378
+ function createEffect(text, color, duration) {
379
+ gameState.effects.push({
380
+ text,
381
+ color,
382
+ x: gameState.plane.x,
383
+ y: gameState.plane.y - 50,
384
+ alpha: 1,
385
+ duration,
386
+ startTime: Date.now()
387
+ });
388
+ }
389
+
390
+ // 更新UI
391
+ function updateUI() {
392
+ scoreDisplay.textContent = gameState.score;
393
+ livesDisplay.textContent = gameState.lives;
394
+ speedDisplay.textContent = Math.floor(gameState.speed);
395
+ ammoDisplay.textContent = gameState.ammo === Infinity ? "∞" : gameState.ammo;
396
+
397
+ // 更新道具状态显示
398
+ powerupStatus.innerHTML = '';
399
+
400
+ if (gameState.plane.powerups.rapidFire > Date.now()) {
401
+ const timeLeft = Math.ceil((gameState.plane.powerups.rapidFire - Date.now()) / 1000);
402
+ powerupStatus.innerHTML += `
403
+ <div class="bg-black bg-opacity-50 px-3 py-1 rounded-lg flex items-center" title="火力增强 (${timeLeft}s)">
404
+ <i class="fas fa-bolt text-red-500 mr-2"></i>
405
+ </div>
406
+ `;
407
+ }
408
+
409
+ if (gameState.plane.powerups.homingMissiles > Date.now()) {
410
+ const timeLeft = Math.ceil((gameState.plane.powerups.homingMissiles - Date.now()) / 1000);
411
+ powerupStatus.innerHTML += `
412
+ <div class="bg-black bg-opacity-50 px-3 py-1 rounded-lg flex items-center" title="跟踪导弹 (${timeLeft}s)">
413
+ <i class="fas fa-rocket text-purple-500 mr-2"></i>
414
+ </div>
415
+ `;
416
+ }
417
+
418
+ if (gameState.plane.hasShield && gameState.plane.shieldDuration > Date.now()) {
419
+ const timeLeft = Math.ceil((gameState.plane.shieldDuration - Date.now()) / 1000);
420
+ powerupStatus.innerHTML += `
421
+ <div class="bg-black bg-opacity-50 px-3 py-1 rounded-lg flex items-center" title="保护罩 (${timeLeft}s)">
422
+ <i class="fas fa-shield-alt text-blue-500 mr-2"></i>
423
+ </div>
424
+ `;
425
+ }
426
+ }
427
+
428
  // 初始化游戏
429
  function initGame() {
430
  gameState.isMobile = detectMobile();
 
444
  velocity: 0,
445
  verticalVelocity: 0,
446
  rotation: 0,
447
+ lastFireTime: 0,
448
+ fireRate: 200,
449
+ bulletDamage: 1,
450
+ hasShield: false,
451
+ shieldDuration: 0,
452
+ powerups: {
453
+ rapidFire: 0,
454
+ homingMissiles: 0,
455
+ }
456
  };
457
  gameState.stars = [];
458
  gameState.obstacles = [];
 
460
  gameState.explosions = [];
461
  gameState.bullets = [];
462
  gameState.debris = [];
463
+ gameState.powerups = [];
464
+ gameState.homingMissiles = [];
465
+ gameState.effects = [];
466
  gameState.lastStarTime = 0;
467
  gameState.lastObstacleTime = 0;
468
  gameState.lastCloudTime = 0;
469
+ gameState.lastPowerupTime = 0;
470
 
471
  startScreen.classList.add('hidden');
472
  gameOverScreen.classList.add('hidden');
 
553
  });
554
  }
555
 
556
+ // 创建道具
557
+ function createPowerup() {
558
+ const size = 40;
559
+ const x = canvas.width + size;
560
+ const y = Math.random() * (canvas.height - size * 2) + size;
561
+ const speed = Math.random() * 2 + 1;
562
+
563
+ // 随机选择一种道具类型
564
+ const powerupKeys = Object.keys(POWERUP_TYPES);
565
+ const randomPowerup = POWERUP_TYPES[powerupKeys[Math.floor(Math.random() * powerupKeys.length)]];
566
+
567
+ gameState.powerups.push({
568
+ x,
569
+ y,
570
+ size,
571
+ speed,
572
+ type: randomPowerup
573
+ });
574
+ }
575
+
576
+ // 创建跟踪导弹
577
+ function createHomingMissile() {
578
+ if (gameState.obstacles.length === 0) return; // 没有目标时不开火
579
+
580
+ // 找到最近的障碍物作为目标
581
+ let closestObstacle = null;
582
+ let minDistance = Infinity;
583
+
584
+ gameState.obstacles.forEach(obstacle => {
585
+ const dx = obstacle.x - gameState.plane.x;
586
+ const dy = obstacle.y - gameState.plane.y;
587
+ const distance = Math.sqrt(dx * dx + dy * dy);
588
+
589
+ if (distance < minDistance) {
590
+ minDistance = distance;
591
+ closestObstacle = obstacle;
592
+ }
593
+ });
594
+
595
+ if (!closestObstacle) return;
596
+
597
+ const size = 12;
598
+ gameState.homingMissiles.push({
599
+ x: gameState.plane.x,
600
+ y: gameState.plane.y,
601
+ size,
602
+ speed: 8,
603
+ target: closestObstacle,
604
+ angle: Math.atan2(
605
+ closestObstacle.y - gameState.plane.y,
606
+ closestObstacle.x - gameState.plane.x
607
+ )
608
+ });
609
+ }
610
+
611
+ // 创建碎片
612
  function createDebris(obstacle, count = 5) {
613
  for (let i = 0; i < count; i++) {
614
  gameState.debris.push({
 
629
  function createBullet() {
630
  if (gameState.ammo <= 0) return false; // 没有弹药了
631
 
632
+ const size = gameState.plane.powerups.rapidFire > Date.now() ? 10 : 8; // 火力增强时子弹更大
633
+ const damage = gameState.plane.powerups.rapidFire > Date.now() ? 2 : 1; // 火力增强时伤害更高
634
+ const speed = gameState.plane.powerups.rapidFire > Date.now() ? 18 : 15; // 火力增强时速度更快
635
  const x = gameState.plane.x + 30; // 从飞机前端发射
636
  const y = gameState.plane.y;
637
 
 
639
  x,
640
  y,
641
  size,
642
+ speed,
643
+ damage
644
  });
645
 
646
+ // 如果有跟踪导弹能力且冷却结束
647
+ if (gameState.plane.powerups.homingMissiles > Date.now() &&
648
+ Math.random() > 0.7) { // 70%概率发射跟踪导弹
649
+ requestAnimationFrame(createHomingMissile);
650
+ }
651
+
652
  // 如果弹药不是无限的,减少弹药
653
  if (gameState.ammo !== Infinity) {
654
  gameState.ammo--;
 
670
  });
671
  }
672
 
 
 
 
 
 
 
 
 
673
  // 检测碰撞
674
  function checkCollision(rect1, rect2) {
675
  return (
 
719
 
720
  // 处理开火
721
  if ((gameState.keys.Space || gameState.isFiring) &&
722
+ timestamp - gameState.plane.lastFireTime > gameState.plane.fireRate) { // 射击冷却
723
  createBullet();
724
  gameState.plane.lastFireTime = timestamp;
725
  }
726
 
727
+ // 检查道具是否过期
728
+ if (gameState.plane.powerups.rapidFire > 0 && gameState.plane.powerups.rapidFire < Date.now()) {
729
+ gameState.plane.powerups.rapidFire = 0;
730
+ gameState.plane.fireRate = 200; // 恢复默认射击速度
731
+ createEffect('火力增强结束', 'red', 1500);
732
+ }
733
+
734
+ if (gameState.plane.powerups.homingMissiles > 0 && gameState.plane.powerups.homingMissiles < Date.now()) {
735
+ gameState.plane.powerups.homingMissiles = 0;
736
+ createEffect('跟踪导弹结束', 'purple', 1500);
737
+ }
738
+
739
+ if (gameState.plane.hasShield && gameState.plane.shieldDuration < Date.now()) {
740
+ gameState.plane.hasShield = false;
741
+ createEffect('保护罩消失', 'blue', 1500);
742
+ }
743
+
744
  // 更新飞机速度
745
  if (gameState.keys.ArrowUp || gameState.keys.ArrowDown) {
746
  gameState.speed = Math.max(50,
 
802
  gameState.lastCloudTime = timestamp;
803
  }
804
 
805
+ // 生成新道具 (每5-8秒)
806
+ if (timestamp - gameState.lastPowerupTime > (Math.random() * 3000 + 5000) / gameState.difficulty) {
807
+ createPowerup();
808
+ gameState.lastPowerupTime = timestamp;
809
+ }
810
+
811
+ // 更新特效
812
+ gameState.effects = gameState.effects.filter(effect =>
813
+ Date.now() - effect.startTime < effect.duration
814
+ );
815
+
816
  // 更新碎片
817
  gameState.debris.forEach(debris => {
818
  debris.x += debris.speedX;
 
822
  });
823
  gameState.debris = gameState.debris.filter(debris => debris.opacity > 0);
824
 
825
+ // 更新跟踪导弹
826
+ gameState.homingMissiles.forEach(missile => {
827
+ if (!missile.target || missile.target.hit) {
828
+ // 如果没有目标或目标已被击中,则直线飞行
829
+ missile.x += Math.cos(missile.angle) * missile.speed;
830
+ missile.y += Math.sin(missile.angle) * missile.speed;
831
+ } else {
832
+ // 计算新的角度以跟踪目标
833
+ const dx = missile.target.x - missile.x;
834
+ const dy = missile.target.y - missile.y;
835
+ const targetAngle = Math.atan2(dy, dx);
836
+
837
+ // 平滑转向
838
+ let angleDiff = targetAngle - missile.angle;
839
+ if (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
840
+ if (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
841
+
842
+ missile.angle += angleDiff * 0.1;
843
+ missile.x += Math.cos(missile.angle) * missile.speed;
844
+ missile.y += Math.sin(missile.angle) * missile.speed;
845
+
846
+ // 检测碰撞
847
+ const missileRect = {
848
+ x: missile.x - missile.size / 2,
849
+ y: missile.y - missile.size / 2,
850
+ width: missile.size,
851
+ height: missile.size
852
+ };
853
+
854
+ const targetRect = {
855
+ x: missile.target.x - missile.target.width / 2,
856
+ y: missile.target.y - missile.target.height / 2,
857
+ width: missile.target.width,
858
+ height: missile.target.height
859
+ };
860
+
861
+ if (checkCollision(missileRect, targetRect)) {
862
+ missile.hit = true;
863
+ missile.target.health -= 3; // 导弹伤害更高
864
+
865
+ if (missile.target.health <= 0) {
866
+ missile.target.hit = true;
867
+ gameState.score += missile.target.isLarge ? 30 : 15;
868
+ updateUI();
869
+
870
+ // 如果是大型障碍物,分裂成小型障碍物
871
+ if (missile.target.isLarge) {
872
+ for (let i = 0; i < 3; i++) {
873
+ gameState.obstacles.push({
874
+ x: missile.target.x + (Math.random() - 0.5) * 50,
875
+ y: missile.target.y + (Math.random() - 0.5) * 50,
876
+ width: missile.target.width / 2,
877
+ height: missile.target.height / 2,
878
+ speed: missile.target.speed * 1.2,
879
+ type: missile.target.type,
880
+ health: 1,
881
+ maxHealth: 1,
882
+ isLarge: false
883
+ });
884
+ }
885
+ }
886
+
887
+ // 创建碎片效果
888
+ createDebris(missile.target, 12);
889
+ }
890
+
891
+ // 创建爆炸效果
892
+ createExplosion(missile.x, missile.y);
893
+ }
894
+ }
895
+ });
896
+ gameState.homingMissiles = gameState.homingMissiles.filter(missile =>
897
+ missile.x < canvas.width && missile.x > 0 &&
898
+ missile.y < canvas.height && missile.y > 0 &&
899
+ !missile.hit
900
+ );
901
+
902
  // 更新云朵
903
  gameState.clouds.forEach(cloud => {
904
  cloud.x -= cloud.speed;
905
  });
906
  gameState.clouds = gameState.clouds.filter(cloud => cloud.x + cloud.size > 0);
907
 
908
+ // 更新道具
909
+ gameState.powerups.forEach(powerup => {
910
+ powerup.x -= powerup.speed;
911
+
912
+ // 检测与飞机的碰撞
913
+ const planeRect = {
914
+ x: gameState.plane.x - gameState.plane.width / 2,
915
+ y: gameState.plane.y - gameState.plane.height / 2,
916
+ width: gameState.plane.width,
917
+ height: gameState.plane.height
918
+ };
919
+
920
+ const powerupRect = {
921
+ x: powerup.x - powerup.size / 2,
922
+ y: powerup.y - powerup.size / 2,
923
+ width: powerup.size,
924
+ height: powerup.size
925
+ };
926
+
927
+ if (checkCollision(planeRect, powerupRect) && !gameState.gameOver) {
928
+ powerup.collected = true;
929
+ powerup.type.effect(gameState);
930
+ updateUI();
931
+ }
932
+ });
933
+ gameState.powerups = gameState.powerups.filter(powerup =>
934
+ powerup.x + powerup.size > 0 && !powerup.collected
935
+ );
936
+
937
  // 更新子弹
938
  gameState.bullets.forEach(bullet => {
939
  bullet.x += bullet.speed;
 
993
  };
994
 
995
  if (checkCollision(planeRect, obstacleRect) && !gameState.gameOver) {
996
+ // 如果有保护罩则不会受伤
997
+ if (!gameState.plane.hasShield || gameState.plane.shieldDuration < Date.now()) {
998
+ obstacle.hit = true;
999
+ gameState.lives--;
1000
+ updateUI();
1001
+ createExplosion(gameState.plane.x, gameState.plane.y);
1002
+
1003
+ if (gameState.lives <= 0) {
1004
+ endGame();
1005
+ }
1006
+ } else {
1007
+ // 保护罩被击中
1008
+ obstacle.hit = true;
1009
+ createExplosion(obstacle.x, obstacle.y);
1010
+ createDebris(obstacle, 4);
1011
  }
1012
  }
1013
 
 
1024
  };
1025
 
1026
  if (checkCollision(bulletRect, obstacleRect)) {
1027
+ obstacle.health -= bullet.damage;
1028
  bulletHits.push(bulletIndex);
1029
  createExplosion(bullet.x, bullet.y);
1030
 
 
1114
  ctx.restore();
1115
  });
1116
 
1117
+ // 绘制道具
1118
+ gameState.powerups.forEach(powerup => {
1119
+ ctx.save();
1120
+ ctx.translate(powerup.x, powerup.y);
1121
+
1122
+ // 绘制闪光效果
1123
+ ctx.beginPath();
1124
+ ctx.arc(0, 0, powerup.size / 2, 0, Math.PI * 2);
1125
+ const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, powerup.size / 2);
1126
+ gradient.addColorStop(0, powerup.type.color);
1127
+ gradient.addColorStop(1, 'rgba(255,255,255,0)');
1128
+ ctx.fillStyle = gradient;
1129
+ ctx.globalAlpha = 0.3;
1130
+ ctx.fill();
1131
+ ctx.globalAlpha = 1;
1132
+
1133
+ // 绘制道具图标
1134
+ ctx.fillStyle = powerup.type.color;
1135
+ ctx.beginPath();
1136
+ ctx.arc(0, 0, powerup.size / 2 - 3, 0, Math.PI * 2);
1137
+ ctx.fill();
1138
+
1139
+ // 绘制边框
1140
+ ctx.strokeStyle = 'white';
1141
+ ctx.lineWidth = 2;
1142
+ ctx.stroke();
1143
+
1144
+ // 绘制道具图标
1145
+ ctx.fillStyle = 'white';
1146
+ ctx.font = '20px FontAwesome';
1147
+ ctx.textAlign = 'center';
1148
+ ctx.textBaseline = 'middle';
1149
+ ctx.fillText(String.fromCharCode(parseInt(getIconCode(powerup.type.icon), 16)), 0, 1);
1150
+
1151
+ ctx.restore();
1152
+ });
1153
+
1154
+ // 绘制跟踪导弹
1155
+ gameState.homingMissiles.forEach(missile => {
1156
+ ctx.save();
1157
+ ctx.translate(missile.x, missile.y);
1158
+ ctx.rotate(missile.angle);
1159
+
1160
+ // 导弹主体
1161
+ ctx.fillStyle = 'red';
1162
+ ctx.beginPath();
1163
+ ctx.moveTo(missile.size / 2, 0);
1164
+ ctx.lineTo(-missile.size / 2, -missile.size / 3);
1165
+ ctx.lineTo(-missile.size / 2, missile.size / 3);
1166
+ ctx.closePath();
1167
+ ctx.fill();
1168
+
1169
+ // 火焰效果
1170
+ ctx.fillStyle = 'orange';
1171
+ ctx.beginPath();
1172
+ ctx.moveTo(-missile.size / 2, -missile.size / 4);
1173
+ ctx.lineTo(-missile.size, 0);
1174
+ ctx.lineTo(-missile.size / 2, missile.size / 4);
1175
+ ctx.closePath();
1176
+ ctx.fill();
1177
+
1178
+ ctx.restore();
1179
+ });
1180
+
1181
  // 绘制子弹
1182
  gameState.bullets.forEach(bullet => {
1183
  const gradient = ctx.createRadialGradient(
 
1342
  ctx.translate(gameState.plane.x, gameState.plane.y);
1343
  ctx.rotate(gameState.plane.rotation * Math.PI / 180);
1344
 
1345
+ // 绘制保护罩
1346
+ if (gameState.plane.hasShield && gameState.plane.shieldDuration > Date.now()) {
1347
+ ctx.beginPath();
1348
+ ctx.arc(0, 0, 45, 0, Math.PI * 2);
1349
+ ctx.strokeStyle = `rgba(0, 204, 255, ${0.3 + Math.sin(Date.now() / 200) * 0.3})`;
1350
+ ctx.lineWidth = 3;
1351
+ ctx.stroke();
1352
+
1353
+ // 保护罩光晕
1354
+ const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 45);
1355
+ gradient.addColorStop(0, 'rgba(0, 204, 255, 0.2)');
1356
+ gradient.addColorStop(1, 'rgba(0, 204, 255, 0)');
1357
+ ctx.fillStyle = gradient;
1358
+ ctx.fill();
1359
+ }
1360
+
1361
  // 飞机主体
1362
  ctx.beginPath();
1363
  ctx.moveTo(30, 0);
 
1435
  ctx.restore();
1436
  });
1437
 
1438
+ // 绘制特效文字
1439
+ gameState.effects.forEach(effect => {
1440
+ const timePassed = Date.now() - effect.startTime;
1441
+ const progress = timePassed / effect.duration;
1442
+
1443
+ ctx.save();
1444
+ ctx.translate(effect.x, effect.y - progress * 50); // 文字向上移动
1445
+ ctx.globalAlpha = 1 - progress * 0.8;
1446
+
1447
+ ctx.font = 'bold 20px Arial';
1448
+ ctx.fillStyle = effect.color;
1449
+ ctx.textAlign = 'center';
1450
+ ctx.textBaseline = 'middle';
1451
+ ctx.fillText(effect.text, 0, 0);
1452
+
1453
+ ctx.restore();
1454
+ });
1455
+
1456
  // 绘制速度线
1457
  if (gameState.speed > 120) {
1458
  for (let i = 0; i < 10; i++) {
 
1488
  }
1489
  }
1490
 
1491
+ // 辅助函数: 获取FontAwesome图标的Unicode
1492
+ function getIconCode(iconClass) {
1493
+ const icons = {
1494
+ 'fas fa-bolt': 'f0e7',
1495
+ 'fas fa-rocket': 'f135',
1496
+ 'fas fa-shield-alt': 'f3ed',
1497
+ 'fas fa-heart': 'f004'
1498
+ };
1499
+ return icons[iconClass] || 'f128'; // 默认返回问号图标
1500
+ }
1501
+
1502
  // 事件监听
1503
  window.addEventListener('resize', resizeCanvas);
1504