zdwalter commited on
Commit
1be7e09
·
verified ·
1 Parent(s): 82c4765

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +135 -14
index.html CHANGED
@@ -107,6 +107,11 @@
107
  background: linear-gradient(to right, #ff0, #f80);
108
  border-radius: 50%;
109
  }
 
 
 
 
 
110
  </style>
111
  </head>
112
  <body class="bg-gray-900 text-white flex flex-col items-center justify-center h-screen">
@@ -117,7 +122,7 @@
117
  <div id="startScreen" class="game-overlay flex flex-col items-center justify-center bg-black bg-opacity-70">
118
  <h1 class="text-5xl font-bold mb-6 text-yellow-300">SKY ADVENTURE</h1>
119
  <div class="plane text-6xl mb-8">✈️</div>
120
- <p class="text-xl mb-8 text-center max-w-md px-4">控制飞机躲避障碍物<br>收集星星获得高分!<br>按射击按钮消灭障碍物!</p>
121
  <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">
122
  开始游戏
123
  </button>
@@ -209,6 +214,7 @@
209
  lives: 3,
210
  ammo: Infinity,
211
  speed: 100,
 
212
  plane: {
213
  x: 0,
214
  y: 0,
@@ -224,6 +230,7 @@
224
  clouds: [],
225
  explosions: [],
226
  bullets: [],
 
227
  lastStarTime: 0,
228
  lastObstacleTime: 0,
229
  lastCloudTime: 0,
@@ -281,6 +288,7 @@
281
  gameState.lives = 3;
282
  gameState.ammo = Infinity;
283
  gameState.speed = 100;
 
284
  gameState.plane = {
285
  x: canvas.width / 2,
286
  y: canvas.height / 2,
@@ -296,6 +304,7 @@
296
  gameState.clouds = [];
297
  gameState.explosions = [];
298
  gameState.bullets = [];
 
299
  gameState.lastStarTime = 0;
300
  gameState.lastObstacleTime = 0;
301
  gameState.lastCloudTime = 0;
@@ -370,7 +379,7 @@
370
  const y = Math.random() * (canvas.height - height);
371
  const speed = Math.random() * 2 + 2 + gameState.speed / 50;
372
  const type = Math.random() > 0.5 ? 'rectangle' : 'circle';
373
- const health = type === 'rectangle' ? 2 : 1; // 矩形障碍物需要2发子弹
374
 
375
  gameState.obstacles.push({
376
  x,
@@ -380,10 +389,28 @@
380
  speed,
381
  type,
382
  health,
383
- maxHealth: health
 
384
  });
385
  }
386
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  // 创建子弹
388
  function createBullet() {
389
  if (gameState.ammo <= 0) return false; // 没有弹药了
@@ -473,6 +500,9 @@
473
 
474
  // 更新游戏状态
475
  function updateGame(timestamp) {
 
 
 
476
  // 处理开火
477
  if ((gameState.keys.Space || gameState.isFiring) &&
478
  timestamp - gameState.plane.lastFireTime > 200) { // 射击冷却时间200ms
@@ -524,13 +554,13 @@
524
  gameState.plane.y = Math.max(gameState.plane.height / 2, Math.min(gameState.plane.y, canvas.height - gameState.plane.height / 2));
525
 
526
  // 生成新星星
527
- if (timestamp - gameState.lastStarTime > 2000) {
528
  createStar();
529
  gameState.lastStarTime = timestamp;
530
  }
531
 
532
  // 生成新障碍物
533
- if (timestamp - gameState.lastObstacleTime > 1500) {
534
  createObstacle();
535
  gameState.lastObstacleTime = timestamp;
536
  }
@@ -541,6 +571,15 @@
541
  gameState.lastCloudTime = timestamp;
542
  }
543
 
 
 
 
 
 
 
 
 
 
544
  // 更新云朵
545
  gameState.clouds.forEach(cloud => {
546
  cloud.x -= cloud.speed;
@@ -635,8 +674,28 @@
635
 
636
  if (obstacle.health <= 0) {
637
  obstacle.hit = true;
638
- gameState.score += 15; // 击毁障碍物奖励
639
  updateUI();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
640
  }
641
  }
642
  });
@@ -682,6 +741,23 @@
682
  });
683
  });
684
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
  // 绘制子弹
686
  gameState.bullets.forEach(bullet => {
687
  const gradient = ctx.createRadialGradient(
@@ -756,23 +832,24 @@
756
  if (obstacle.type === 'rectangle') {
757
  // 绘制健康条 (如果是矩形障碍物)
758
  if (obstacle.health < obstacle.maxHealth) {
 
759
  ctx.fillStyle = 'red';
760
  ctx.fillRect(
761
- -obstacle.width / 2 - 2,
762
- -obstacle.height / 2 - 10,
763
- 5,
764
  5
765
  );
766
  ctx.fillStyle = 'lime';
767
  ctx.fillRect(
768
- -obstacle.width / 2 - 2 + 5,
769
- -obstacle.height / 2 - 10,
770
- 5,
771
  5
772
  );
773
  }
774
 
775
- ctx.fillStyle = '#555';
776
  ctx.fillRect(
777
  -obstacle.width / 2,
778
  -obstacle.height / 2,
@@ -781,13 +858,31 @@
781
  );
782
 
783
  // 添加一些细节
784
- ctx.fillStyle = '#444';
785
  ctx.fillRect(
786
  -obstacle.width / 2 + 5,
787
  -obstacle.height / 2 + 5,
788
  obstacle.width - 10,
789
  obstacle.height - 10
790
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
791
  } else {
792
  ctx.beginPath();
793
  ctx.arc(0, 0, obstacle.width / 2, 0, Math.PI * 2);
@@ -799,6 +894,24 @@
799
  ctx.arc(0, 0, obstacle.width / 2 - 5, 0, Math.PI * 2);
800
  ctx.fillStyle = '#444';
801
  ctx.fill();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
802
  }
803
 
804
  ctx.restore();
@@ -911,6 +1024,14 @@
911
  ctx.restore();
912
  }
913
  }
 
 
 
 
 
 
 
 
914
  }
915
 
916
  // 事件监听
 
107
  background: linear-gradient(to right, #ff0, #f80);
108
  border-radius: 50%;
109
  }
110
+ .debris {
111
+ position: absolute;
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
  <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>
 
214
  lives: 3,
215
  ammo: Infinity,
216
  speed: 100,
217
+ difficulty: 1,
218
  plane: {
219
  x: 0,
220
  y: 0,
 
230
  clouds: [],
231
  explosions: [],
232
  bullets: [],
233
+ debris: [],
234
  lastStarTime: 0,
235
  lastObstacleTime: 0,
236
  lastCloudTime: 0,
 
288
  gameState.lives = 3;
289
  gameState.ammo = Infinity;
290
  gameState.speed = 100;
291
+ gameState.difficulty = 1;
292
  gameState.plane = {
293
  x: canvas.width / 2,
294
  y: canvas.height / 2,
 
304
  gameState.clouds = [];
305
  gameState.explosions = [];
306
  gameState.bullets = [];
307
+ gameState.debris = [];
308
  gameState.lastStarTime = 0;
309
  gameState.lastObstacleTime = 0;
310
  gameState.lastCloudTime = 0;
 
379
  const y = Math.random() * (canvas.height - height);
380
  const speed = Math.random() * 2 + 2 + gameState.speed / 50;
381
  const type = Math.random() > 0.5 ? 'rectangle' : 'circle';
382
+ const health = type === 'rectangle' ? (width > 80 ? 3 : 2) : 1;
383
 
384
  gameState.obstacles.push({
385
  x,
 
389
  speed,
390
  type,
391
  health,
392
+ maxHealth: health,
393
+ isLarge: width > 80
394
  });
395
  }
396
 
397
+ // 创建障碍物碎片
398
+ function createDebris(obstacle, count = 5) {
399
+ for (let i = 0; i < count; i++) {
400
+ gameState.debris.push({
401
+ x: obstacle.x,
402
+ y: obstacle.y,
403
+ width: obstacle.width / 3,
404
+ height: obstacle.height / 3,
405
+ speedX: (Math.random() - 0.5) * 4,
406
+ speedY: (Math.random() - 0.5) * 4,
407
+ rotation: 0,
408
+ rotationSpeed: (Math.random() - 0.5) * 0.2,
409
+ opacity: 1
410
+ });
411
+ }
412
+ }
413
+
414
  // 创建子弹
415
  function createBullet() {
416
  if (gameState.ammo <= 0) return false; // 没有弹药了
 
500
 
501
  // 更新游戏状态
502
  function updateGame(timestamp) {
503
+ // 随着分数增加难度
504
+ gameState.difficulty = 1 + Math.min(gameState.score / 1000, 3);
505
+
506
  // 处理开火
507
  if ((gameState.keys.Space || gameState.isFiring) &&
508
  timestamp - gameState.plane.lastFireTime > 200) { // 射击冷却时间200ms
 
554
  gameState.plane.y = Math.max(gameState.plane.height / 2, Math.min(gameState.plane.y, canvas.height - gameState.plane.height / 2));
555
 
556
  // 生成新星星
557
+ if (timestamp - gameState.lastStarTime > 2000 / gameState.difficulty) {
558
  createStar();
559
  gameState.lastStarTime = timestamp;
560
  }
561
 
562
  // 生成新障碍物
563
+ if (timestamp - gameState.lastObstacleTime > 1500 / gameState.difficulty) {
564
  createObstacle();
565
  gameState.lastObstacleTime = timestamp;
566
  }
 
571
  gameState.lastCloudTime = timestamp;
572
  }
573
 
574
+ // 更新碎片
575
+ gameState.debris.forEach(debris => {
576
+ debris.x += debris.speedX;
577
+ debris.y += debris.speedY;
578
+ debris.rotation += debris.rotationSpeed;
579
+ debris.opacity -= 0.02;
580
+ });
581
+ gameState.debris = gameState.debris.filter(debris => debris.opacity > 0);
582
+
583
  // 更新云朵
584
  gameState.clouds.forEach(cloud => {
585
  cloud.x -= cloud.speed;
 
674
 
675
  if (obstacle.health <= 0) {
676
  obstacle.hit = true;
677
+ gameState.score += obstacle.isLarge ? 30 : 15; // 大型障碍物更多分
678
  updateUI();
679
+
680
+ // 如果是大型障碍物,分裂成小型障碍物
681
+ if (obstacle.isLarge) {
682
+ for (let i = 0; i < 3; i++) {
683
+ gameState.obstacles.push({
684
+ x: obstacle.x + (Math.random() - 0.5) * 50,
685
+ y: obstacle.y + (Math.random() - 0.5) * 50,
686
+ width: obstacle.width / 2,
687
+ height: obstacle.height / 2,
688
+ speed: obstacle.speed * 1.2,
689
+ type: obstacle.type,
690
+ health: 1,
691
+ maxHealth: 1,
692
+ isLarge: false
693
+ });
694
+ }
695
+ }
696
+
697
+ // 创建碎片效果
698
+ createDebris(obstacle, 8);
699
  }
700
  }
701
  });
 
741
  });
742
  });
743
 
744
+ // 绘制碎片
745
+ gameState.debris.forEach(debris => {
746
+ ctx.save();
747
+ ctx.translate(debris.x, debris.y);
748
+ ctx.rotate(debris.rotation);
749
+
750
+ ctx.fillStyle = `rgba(100, 100, 100, ${debris.opacity})`;
751
+ ctx.fillRect(
752
+ -debris.width / 2,
753
+ -debris.height / 2,
754
+ debris.width,
755
+ debris.height
756
+ );
757
+
758
+ ctx.restore();
759
+ });
760
+
761
  // 绘制子弹
762
  gameState.bullets.forEach(bullet => {
763
  const gradient = ctx.createRadialGradient(
 
832
  if (obstacle.type === 'rectangle') {
833
  // 绘制健康条 (如果是矩形障碍物)
834
  if (obstacle.health < obstacle.maxHealth) {
835
+ const healthBarWidth = 20;
836
  ctx.fillStyle = 'red';
837
  ctx.fillRect(
838
+ -healthBarWidth / 2,
839
+ -obstacle.height / 2 - 15,
840
+ healthBarWidth,
841
  5
842
  );
843
  ctx.fillStyle = 'lime';
844
  ctx.fillRect(
845
+ -healthBarWidth / 2,
846
+ -obstacle.height / 2 - 15,
847
+ healthBarWidth * (obstacle.health / obstacle.maxHealth),
848
  5
849
  );
850
  }
851
 
852
+ ctx.fillStyle = obstacle.isLarge ? '#333' : '#555';
853
  ctx.fillRect(
854
  -obstacle.width / 2,
855
  -obstacle.height / 2,
 
858
  );
859
 
860
  // 添加一些细节
861
+ ctx.fillStyle = obstacle.isLarge ? '#222' : '#444';
862
  ctx.fillRect(
863
  -obstacle.width / 2 + 5,
864
  -obstacle.height / 2 + 5,
865
  obstacle.width - 10,
866
  obstacle.height - 10
867
  );
868
+
869
+ // 添加裂缝效果 (对于受损的大型障碍物)
870
+ if (obstacle.isLarge && obstacle.health < obstacle.maxHealth) {
871
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
872
+ ctx.lineWidth = 2;
873
+ for (let i = 0; i < 3; i++) {
874
+ ctx.beginPath();
875
+ ctx.moveTo(
876
+ -obstacle.width / 2 + Math.random() * obstacle.width,
877
+ -obstacle.height / 2 + Math.random() * obstacle.height / 3
878
+ );
879
+ ctx.lineTo(
880
+ -obstacle.width / 2 + Math.random() * obstacle.width,
881
+ obstacle.height / 2 - Math.random() * obstacle.height / 3
882
+ );
883
+ ctx.stroke();
884
+ }
885
+ }
886
  } else {
887
  ctx.beginPath();
888
  ctx.arc(0, 0, obstacle.width / 2, 0, Math.PI * 2);
 
894
  ctx.arc(0, 0, obstacle.width / 2 - 5, 0, Math.PI * 2);
895
  ctx.fillStyle = '#444';
896
  ctx.fill();
897
+
898
+ // 添加裂缝效果 (对于受损的大型障碍物)
899
+ if (obstacle.isLarge && obstacle.health < obstacle.maxHealth) {
900
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
901
+ ctx.lineWidth = 2;
902
+ for (let i = 0; i < 3; i++) {
903
+ ctx.beginPath();
904
+ ctx.moveTo(
905
+ Math.cos(i * 2) * obstacle.width / 4,
906
+ Math.sin(i * 2) * obstacle.width / 4
907
+ );
908
+ ctx.lineTo(
909
+ Math.cos(i * 2 + 1) * obstacle.width / 3,
910
+ Math.sin(i * 2 + 1) * obstacle.width / 3
911
+ );
912
+ ctx.stroke();
913
+ }
914
+ }
915
  }
916
 
917
  ctx.restore();
 
1024
  ctx.restore();
1025
  }
1026
  }
1027
+
1028
+ // 绘制难度提示
1029
+ if (gameState.difficulty > 1.5) {
1030
+ ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
1031
+ ctx.font = '20px Arial';
1032
+ ctx.textAlign = 'right';
1033
+ ctx.fillText(`难度: ${gameState.difficulty.toFixed(1)}x`, canvas.width - 20, 30);
1034
+ }
1035
  }
1036
 
1037
  // 事件监听