CYXiaofeng commited on
Commit
42f63d4
·
verified ·
1 Parent(s): f418126

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1584 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Fly Game
3
- emoji: 🏢
4
- colorFrom: gray
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: fly-game
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1584 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>太空射击 - 3D 射击游戏</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.min.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/effects/OutlineEffect.js"></script>
12
+ <style>
13
+ body {
14
+ margin: 0;
15
+ overflow: hidden;
16
+ font-family: 'Arial', sans-serif;
17
+ }
18
+ #game-container {
19
+ position: relative;
20
+ width: 100vw;
21
+ height: 100vh;
22
+ }
23
+ #ui-overlay {
24
+ position: absolute;
25
+ top: 0;
26
+ left: 0;
27
+ width: 100%;
28
+ height: 100%;
29
+ pointer-events: none;
30
+ color: white;
31
+ font-family: 'Orbitron', sans-serif;
32
+ }
33
+ #health-bar {
34
+ position: absolute;
35
+ top: 20px;
36
+ left: 20px;
37
+ width: 200px;
38
+ height: 20px;
39
+ background-color: rgba(255, 0, 0, 0.3);
40
+ border: 2px solid white;
41
+ border-radius: 5px;
42
+ overflow: hidden;
43
+ }
44
+ #health-fill {
45
+ height: 100%;
46
+ width: 100%;
47
+ background-color: #ff3366;
48
+ transition: width 0.3s;
49
+ }
50
+ #score {
51
+ position: absolute;
52
+ top: 20px;
53
+ right: 20px;
54
+ font-size: 24px;
55
+ color: white;
56
+ text-shadow: 0 0 10px #00ffff;
57
+ }
58
+ #level {
59
+ position: absolute;
60
+ top: 60px;
61
+ right: 20px;
62
+ font-size: 18px;
63
+ color: white;
64
+ text-shadow: 0 0 5px #00ffff;
65
+ }
66
+ #ammo {
67
+ position: absolute;
68
+ bottom: 20px;
69
+ left: 20px;
70
+ font-size: 18px;
71
+ color: white;
72
+ text-shadow: 0 0 5px #00ffff;
73
+ }
74
+ #game-over, #level-complete, #start-screen {
75
+ position: absolute;
76
+ top: 0;
77
+ left: 0;
78
+ width: 100%;
79
+ height: 100%;
80
+ display: flex;
81
+ flex-direction: column;
82
+ justify-content: center;
83
+ align-items: center;
84
+ background-color: rgba(0, 0, 0, 0.8);
85
+ color: white;
86
+ font-size: 36px;
87
+ pointer-events: auto;
88
+ }
89
+ .button {
90
+ margin-top: 20px;
91
+ padding: 10px 30px;
92
+ background: linear-gradient(45deg, #ff3366, #00ffff);
93
+ border: none;
94
+ border-radius: 5px;
95
+ color: white;
96
+ font-size: 18px;
97
+ cursor: pointer;
98
+ pointer-events: auto;
99
+ transition: all 0.3s;
100
+ }
101
+ .button:hover {
102
+ transform: scale(1.05);
103
+ box-shadow: 0 0 15px #00ffff;
104
+ }
105
+ #enemy-count {
106
+ position: absolute;
107
+ top: 60px;
108
+ left: 20px;
109
+ font-size: 18px;
110
+ color: white;
111
+ text-shadow: 0 0 5px #00ffff;
112
+ }
113
+ #boss-health {
114
+ position: absolute;
115
+ top: 100px;
116
+ left: 50%;
117
+ transform: translateX(-50%);
118
+ width: 300px;
119
+ height: 20px;
120
+ background-color: rgba(255, 0, 0, 0.3);
121
+ border: 2px solid white;
122
+ border-radius: 5px;
123
+ overflow: hidden;
124
+ display: none;
125
+ }
126
+ #boss-health-fill {
127
+ height: 100%;
128
+ width: 100%;
129
+ background-color: #ff3366;
130
+ transition: width 0.3s;
131
+ }
132
+ #power-ups {
133
+ position: absolute;
134
+ bottom: 60px;
135
+ left: 20px;
136
+ display: flex;
137
+ gap: 10px;
138
+ }
139
+ .power-up-icon {
140
+ width: 40px;
141
+ height: 40px;
142
+ border-radius: 50%;
143
+ display: flex;
144
+ justify-content: center;
145
+ align-items: center;
146
+ font-size: 20px;
147
+ background-color: rgba(255, 255, 255, 0.2);
148
+ border: 2px solid white;
149
+ }
150
+ #crosshair {
151
+ position: absolute;
152
+ top: 50%;
153
+ left: 50%;
154
+ transform: translate(-50%, -50%);
155
+ width: 30px;
156
+ height: 30px;
157
+ pointer-events: none;
158
+ }
159
+ #crosshair::before, #crosshair::after {
160
+ content: '';
161
+ position: absolute;
162
+ background-color: rgba(255, 255, 255, 0.8);
163
+ }
164
+ #crosshair::before {
165
+ width: 30px;
166
+ height: 2px;
167
+ left: 0;
168
+ top: 14px;
169
+ }
170
+ #crosshair::after {
171
+ width: 2px;
172
+ height: 30px;
173
+ left: 14px;
174
+ top: 0;
175
+ }
176
+ #crosshair.active {
177
+ animation: pulse 0.5s infinite alternate;
178
+ }
179
+ @keyframes pulse {
180
+ from { transform: translate(-50%, -50%) scale(1); }
181
+ to { transform: translate(-50%, -50%) scale(1.2); }
182
+ }
183
+ #radar {
184
+ position: absolute;
185
+ bottom: 20px;
186
+ right: 20px;
187
+ width: 150px;
188
+ height: 150px;
189
+ border-radius: 50%;
190
+ background-color: rgba(0, 0, 0, 0.5);
191
+ border: 2px solid #00ffff;
192
+ overflow: hidden;
193
+ }
194
+ #radar-center {
195
+ position: absolute;
196
+ top: 50%;
197
+ left: 50%;
198
+ transform: translate(-50%, -50%);
199
+ width: 2px;
200
+ height: 2px;
201
+ border-radius: 50%;
202
+ background-color: #00ffff;
203
+ }
204
+ .radar-sweep {
205
+ position: absolute;
206
+ top: 0;
207
+ left: 0;
208
+ width: 100%;
209
+ height: 100%;
210
+ border-radius: 50%;
211
+ clip-path: polygon(50% 50%, 50% 0, 50% 0);
212
+ background-color: rgba(0, 255, 255, 0.2);
213
+ animation: radarSweep 3s linear infinite;
214
+ }
215
+ @keyframes radarSweep {
216
+ from { transform: rotate(0deg); }
217
+ to { transform: rotate(360deg); }
218
+ }
219
+ .radar-blip {
220
+ position: absolute;
221
+ width: 6px;
222
+ height: 6px;
223
+ border-radius: 50%;
224
+ background-color: #ff3366;
225
+ transform: translate(-50%, -50%);
226
+ }
227
+ </style>
228
+ </head>
229
+ <body>
230
+ <div id="game-container">
231
+ <div id="ui-overlay">
232
+ <div id="health-bar">
233
+ <div id="health-fill"></div>
234
+ </div>
235
+ <div id="score">分数: 0</div>
236
+ <div id="level">关卡: 1</div>
237
+ <div id="enemy-count">敌人: 0</div>
238
+ <div id="boss-health">
239
+ <div id="boss-health-fill"></div>
240
+ </div>
241
+ <div id="ammo">弹药: ∞</div>
242
+ <div id="power-ups"></div>
243
+ <div id="crosshair"></div>
244
+ <div id="radar">
245
+ <div id="radar-center"></div>
246
+ <div class="radar-sweep"></div>
247
+ </div>
248
+
249
+ <div id="start-screen">
250
+ <h1 class="text-5xl font-bold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-600">太空射击</h1>
251
+ <p class="text-xl mb-8">保卫银河系免受外星入侵</p>
252
+ <button id="start-button" class="button">开始游戏</button>
253
+ <div class="mt-8 text-sm">
254
+ <p>控制方式: WASD移动, 鼠标瞄准射击</p>
255
+ <p>空格键: 特殊武器</p>
256
+ </div>
257
+ </div>
258
+
259
+ <div id="game-over" style="display: none;">
260
+ <h1 class="text-5xl font-bold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-red-400 to-purple-600">游戏结束</h1>
261
+ <p class="text-xl mb-4">最终分数: <span id="final-score">0</span></p>
262
+ <p class="text-xl mb-8">最高关卡: <span id="final-level">1</span></p>
263
+ <button id="restart-button" class="button">重新开始</button>
264
+ </div>
265
+
266
+ <div id="level-complete" style="display: none;">
267
+ <h1 class="text-5xl font-bold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-blue-600">关卡完成!</h1>
268
+ <p class="text-xl mb-4">分数: <span id="level-score">0</span></p>
269
+ <p class="text-xl mb-8">下一关卡: <span id="next-level">2</span></p>
270
+ <button id="next-level-button" class="button">继续</button>
271
+ </div>
272
+ </div>
273
+ </div>
274
+
275
+ <script>
276
+ // 游戏常量
277
+ const GAME = {
278
+ WIDTH: window.innerWidth,
279
+ HEIGHT: window.innerHeight,
280
+ ASPECT: window.innerWidth / window.innerHeight,
281
+ NEAR: 0.1,
282
+ FAR: 10000,
283
+ FOV: 75,
284
+ PLAYER_SPEED: 0.3,
285
+ BULLET_SPEED: 1.5,
286
+ ENEMY_SPEED: 0.1,
287
+ BOSS_SPEED: 0.05,
288
+ POWERUP_DURATION: 10000, // 10秒
289
+ LEVELS: [
290
+ { enemies: 10, enemyHealth: 1, spawnRate: 1000, boss: false },
291
+ { enemies: 15, enemyHealth: 2, spawnRate: 800, boss: false },
292
+ { enemies: 20, enemyHealth: 3, spawnRate: 600, boss: false },
293
+ { enemies: 25, enemyHealth: 4, spawnRate: 500, boss: true },
294
+ { enemies: 30, enemyHealth: 5, spawnRate: 400, boss: false },
295
+ { enemies: 35, enemyHealth: 6, spawnRate: 300, boss: false },
296
+ { enemies: 40, enemyHealth: 7, spawnRate: 200, boss: true },
297
+ { enemies: 50, enemyHealth: 8, spawnRate: 100, boss: true }
298
+ ]
299
+ };
300
+
301
+ // 游戏状态
302
+ let gameState = {
303
+ score: 0,
304
+ level: 1,
305
+ health: 100,
306
+ maxHealth: 100,
307
+ ammo: Infinity,
308
+ gameOver: false,
309
+ levelComplete: false,
310
+ enemies: [],
311
+ bullets: [],
312
+ enemyBullets: [],
313
+ powerUps: [],
314
+ activePowerUps: {},
315
+ boss: null,
316
+ bossActive: false,
317
+ enemiesSpawned: 0,
318
+ enemiesDestroyed: 0,
319
+ lastShot: 0,
320
+ shotDelay: 200,
321
+ lastEnemyShot: 0,
322
+ enemyShotDelay: 1000,
323
+ lastPowerUpSpawn: 0,
324
+ powerUpSpawnDelay: 15000,
325
+ specialWeaponReady: true,
326
+ specialWeaponCooldown: 10000,
327
+ lastSpecialWeaponUse: 0
328
+ };
329
+
330
+ // Three.js 变量
331
+ let scene, camera, renderer, controls, effect;
332
+ let player, playerGroup;
333
+ let clock = new THREE.Clock();
334
+ let raycaster = new THREE.Raycaster();
335
+ let mouse = new THREE.Vector2();
336
+ let isMouseDown = false;
337
+ let keys = {};
338
+ let radarBlips = [];
339
+
340
+ // 初始化游戏
341
+ function init() {
342
+ // 创建场景
343
+ scene = new THREE.Scene();
344
+ scene.background = new THREE.Color(0x000000);
345
+ scene.fog = new THREE.FogExp2(0x000000, 0.0005);
346
+
347
+ // 创建相机
348
+ camera = new THREE.PerspectiveCamera(GAME.FOV, GAME.ASPECT, GAME.NEAR, GAME.FAR);
349
+ camera.position.set(0, 5, 15);
350
+ camera.lookAt(0, 0, 0);
351
+
352
+ // 创建渲染器
353
+ renderer = new THREE.WebGLRenderer({ antialias: true });
354
+ renderer.setSize(GAME.WIDTH, GAME.HEIGHT);
355
+ renderer.shadowMap.enabled = true;
356
+ document.getElementById('game-container').appendChild(renderer.domElement);
357
+
358
+ // 添加轮廓效果
359
+ effect = new THREE.OutlineEffect(renderer);
360
+
361
+ // 添加灯光
362
+ addLights();
363
+
364
+ // 添加星空背景
365
+ createStarfield();
366
+
367
+ // 创建玩家飞船
368
+ createPlayer();
369
+
370
+ // 添加事件监听器
371
+ setupEventListeners();
372
+
373
+ // 显示开始屏幕
374
+ document.getElementById('start-screen').style.display = 'flex';
375
+
376
+ // 开始游戏循环
377
+ animate();
378
+ }
379
+
380
+ // 添加灯光
381
+ function addLights() {
382
+ // 环境光
383
+ const ambientLight = new THREE.AmbientLight(0x404040);
384
+ scene.add(ambientLight);
385
+
386
+ // 方向光
387
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
388
+ directionalLight.position.set(1, 1, 1);
389
+ directionalLight.castShadow = true;
390
+ directionalLight.shadow.mapSize.width = 1024;
391
+ directionalLight.shadow.mapSize.height = 1024;
392
+ scene.add(directionalLight);
393
+
394
+ // 点光源
395
+ const pointLight = new THREE.PointLight(0x00ffff, 2, 50);
396
+ pointLight.position.set(0, 5, 0);
397
+ scene.add(pointLight);
398
+
399
+ // 聚光灯
400
+ const spotLight = new THREE.SpotLight(0xffffff, 1);
401
+ spotLight.position.set(0, 10, 0);
402
+ spotLight.castShadow = true;
403
+ spotLight.shadow.mapSize.width = 1024;
404
+ spotLight.shadow.mapSize.height = 1024;
405
+ scene.add(spotLight);
406
+ }
407
+
408
+ // 创建星空背景
409
+ function createStarfield() {
410
+ const starGeometry = new THREE.BufferGeometry();
411
+ const starMaterial = new THREE.PointsMaterial({
412
+ color: 0xffffff,
413
+ size: 0.1,
414
+ transparent: true,
415
+ opacity: 0.8
416
+ });
417
+
418
+ const stars = [];
419
+ for (let i = 0; i < 5000; i++) {
420
+ const x = (Math.random() - 0.5) * 2000;
421
+ const y = (Math.random() - 0.5) * 2000;
422
+ const z = (Math.random() - 0.5) * 2000;
423
+ stars.push(x, y, z);
424
+ }
425
+
426
+ starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(stars, 3));
427
+ const starField = new THREE.Points(starGeometry, starMaterial);
428
+ scene.add(starField);
429
+ }
430
+
431
+ // 创建玩家飞船
432
+ function createPlayer() {
433
+ playerGroup = new THREE.Group();
434
+
435
+ // 创建飞船主体
436
+ const geometry = new THREE.ConeGeometry(0.5, 1.5, 4);
437
+ const material = new THREE.MeshPhongMaterial({
438
+ color: 0x3366ff,
439
+ emissive: 0x0044cc,
440
+ specular: 0xffffff,
441
+ shininess: 30,
442
+ flatShading: true
443
+ });
444
+ player = new THREE.Mesh(geometry, material);
445
+ player.rotation.x = Math.PI / 2;
446
+ player.position.y = 0.5;
447
+ player.castShadow = true;
448
+
449
+ // 添加引擎火焰
450
+ const flameGeometry = new THREE.ConeGeometry(0.3, 1, 4);
451
+ const flameMaterial = new THREE.MeshBasicMaterial({
452
+ color: 0xff6600,
453
+ transparent: true,
454
+ opacity: 0.8
455
+ });
456
+ const flame = new THREE.Mesh(flameGeometry, flameMaterial);
457
+ flame.rotation.x = Math.PI / 2;
458
+ flame.position.z = -1;
459
+ player.add(flame);
460
+
461
+ // 添加机翼
462
+ const wingGeometry = new THREE.BoxGeometry(1, 0.1, 0.5);
463
+ const wingMaterial = new THREE.MeshPhongMaterial({
464
+ color: 0x3366ff,
465
+ emissive: 0x0044cc,
466
+ specular: 0xffffff,
467
+ shininess: 30,
468
+ flatShading: true
469
+ });
470
+
471
+ const leftWing = new THREE.Mesh(wingGeometry, wingMaterial);
472
+ leftWing.position.set(-0.8, 0, 0);
473
+ player.add(leftWing);
474
+
475
+ const rightWing = new THREE.Mesh(wingGeometry, wingMaterial);
476
+ rightWing.position.set(0.8, 0, 0);
477
+ player.add(rightWing);
478
+
479
+ playerGroup.add(player);
480
+ playerGroup.position.set(0, 0, -10);
481
+ scene.add(playerGroup);
482
+ }
483
+
484
+ // 创建敌人
485
+ function createEnemy(x, y, z, health = 1) {
486
+ const enemyGroup = new THREE.Group();
487
+
488
+ // 创建敌人主体
489
+ const geometry = new THREE.OctahedronGeometry(0.6);
490
+ const material = new THREE.MeshPhongMaterial({
491
+ color: health > 3 ? 0xff0000 : (health > 1 ? 0xff9900 : 0x00ff00),
492
+ emissive: health > 3 ? 0x990000 : (health > 1 ? 0x994400 : 0x009900),
493
+ specular: 0xffffff,
494
+ shininess: 30,
495
+ flatShading: true
496
+ });
497
+ const enemy = new THREE.Mesh(geometry, material);
498
+ enemy.castShadow = true;
499
+ enemy.userData.health = health;
500
+ enemy.userData.maxHealth = health;
501
+
502
+ // 添加细节
503
+ const eyeGeometry = new THREE.SphereGeometry(0.1);
504
+ const eyeMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
505
+
506
+ const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
507
+ leftEye.position.set(-0.2, 0.2, 0.5);
508
+ enemy.add(leftEye);
509
+
510
+ const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
511
+ rightEye.position.set(0.2, 0.2, 0.5);
512
+ enemy.add(rightEye);
513
+
514
+ enemyGroup.add(enemy);
515
+ enemyGroup.position.set(x, y, z);
516
+ enemyGroup.userData.speed = GAME.ENEMY_SPEED * (1 + Math.random() * 0.5);
517
+ enemyGroup.userData.isBoss = false;
518
+
519
+ scene.add(enemyGroup);
520
+ gameState.enemies.push(enemyGroup);
521
+
522
+ return enemyGroup;
523
+ }
524
+
525
+ // 创建Boss敌人
526
+ function createBoss() {
527
+ const bossGroup = new THREE.Group();
528
+
529
+ // 创建Boss主体
530
+ const geometry = new THREE.DodecahedronGeometry(2);
531
+ const material = new THREE.MeshPhongMaterial({
532
+ color: 0xff0000,
533
+ emissive: 0x990000,
534
+ specular: 0xffffff,
535
+ shininess: 30,
536
+ flatShading: true
537
+ });
538
+ const boss = new THREE.Mesh(geometry, material);
539
+ boss.castShadow = true;
540
+ boss.userData.health = 20;
541
+ boss.userData.maxHealth = 20;
542
+
543
+ // 添加细节
544
+ const eyeGeometry = new THREE.SphereGeometry(0.3);
545
+ const eyeMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
546
+
547
+ const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
548
+ leftEye.position.set(-0.8, 0.5, 1.8);
549
+ boss.add(leftEye);
550
+
551
+ const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
552
+ rightEye.position.set(0.8, 0.5, 1.8);
553
+ boss.add(rightEye);
554
+
555
+ // 添加武器
556
+ const weaponGeometry = new THREE.CylinderGeometry(0.2, 0.2, 1, 6);
557
+ const weaponMaterial = new THREE.MeshPhongMaterial({
558
+ color: 0x666666,
559
+ emissive: 0x333333,
560
+ specular: 0xffffff,
561
+ shininess: 30,
562
+ flatShading: true
563
+ });
564
+
565
+ const leftWeapon = new THREE.Mesh(weaponGeometry, weaponMaterial);
566
+ leftWeapon.position.set(-1.5, 0, 0);
567
+ leftWeapon.rotation.z = Math.PI / 2;
568
+ boss.add(leftWeapon);
569
+
570
+ const rightWeapon = new THREE.Mesh(weaponGeometry, weaponMaterial);
571
+ rightWeapon.position.set(1.5, 0, 0);
572
+ rightWeapon.rotation.z = Math.PI / 2;
573
+ boss.add(rightWeapon);
574
+
575
+ bossGroup.add(boss);
576
+ bossGroup.position.set(0, 0, 50);
577
+ bossGroup.userData.speed = GAME.BOSS_SPEED;
578
+ bossGroup.userData.isBoss = true;
579
+ bossGroup.userData.lastShot = 0;
580
+ bossGroup.userData.shotDelay = 500;
581
+
582
+ scene.add(bossGroup);
583
+ gameState.enemies.push(bossGroup);
584
+ gameState.boss = bossGroup;
585
+ gameState.bossActive = true;
586
+
587
+ // 显示Boss血条
588
+ document.getElementById('boss-health').style.display = 'block';
589
+ updateBossHealth();
590
+
591
+ return bossGroup;
592
+ }
593
+
594
+ // 创建子弹
595
+ function createBullet(x, y, z, isEnemy = false) {
596
+ const bulletGroup = new THREE.Group();
597
+
598
+ const geometry = new THREE.SphereGeometry(0.1);
599
+ const material = new THREE.MeshPhongMaterial({
600
+ color: isEnemy ? 0xff0000 : 0x00ffff,
601
+ emissive: isEnemy ? 0x990000 : 0x006666,
602
+ specular: 0xffffff,
603
+ shininess: 30,
604
+ flatShading: true
605
+ });
606
+ const bullet = new THREE.Mesh(geometry, material);
607
+ bullet.castShadow = true;
608
+
609
+ // 添加光晕效果
610
+ const glowGeometry = new THREE.SphereGeometry(0.2);
611
+ const glowMaterial = new THREE.MeshBasicMaterial({
612
+ color: isEnemy ? 0xff0000 : 0x00ffff,
613
+ transparent: true,
614
+ opacity: 0.5
615
+ });
616
+ const glow = new THREE.Mesh(glowGeometry, glowMaterial);
617
+ bullet.add(glow);
618
+
619
+ bulletGroup.add(bullet);
620
+ bulletGroup.position.set(x, y, z);
621
+ bulletGroup.userData.isEnemy = isEnemy;
622
+ bulletGroup.userData.speed = isEnemy ? GAME.BULLET_SPEED * 0.8 : GAME.BULLET_SPEED;
623
+
624
+ scene.add(bulletGroup);
625
+
626
+ if (isEnemy) {
627
+ gameState.enemyBullets.push(bulletGroup);
628
+ } else {
629
+ gameState.bullets.push(bulletGroup);
630
+ }
631
+
632
+ return bulletGroup;
633
+ }
634
+
635
+ // 创建能量道具
636
+ function createPowerUp(x, y, z) {
637
+ const powerUpGroup = new THREE.Group();
638
+
639
+ const geometry = new THREE.IcosahedronGeometry(0.4);
640
+ const material = new THREE.MeshPhongMaterial({
641
+ color: 0xffff00,
642
+ emissive: 0x996600,
643
+ specular: 0xffffff,
644
+ shininess: 30,
645
+ flatShading: true,
646
+ transparent: true,
647
+ opacity: 0.9
648
+ });
649
+ const powerUp = new THREE.Mesh(geometry, material);
650
+ powerUp.castShadow = true;
651
+
652
+ // 随机选择道具类型
653
+ const types = ['health', 'shield', 'speed', 'fireRate', 'special'];
654
+ const type = types[Math.floor(Math.random() * types.length)];
655
+ powerUp.userData.type = type;
656
+
657
+ // 根据类型改变颜色
658
+ switch (type) {
659
+ case 'health':
660
+ powerUp.material.color.setHex(0x00ff00);
661
+ powerUp.material.emissive.setHex(0x009900);
662
+ break;
663
+ case 'shield':
664
+ powerUp.material.color.setHex(0x3366ff);
665
+ powerUp.material.emissive.setHex(0x003399);
666
+ break;
667
+ case 'speed':
668
+ powerUp.material.color.setHex(0xff9900);
669
+ powerUp.material.emissive.setHex(0x994400);
670
+ break;
671
+ case 'fireRate':
672
+ powerUp.material.color.setHex(0xff00ff);
673
+ powerUp.material.emissive.setHex(0x990099);
674
+ break;
675
+ case 'special':
676
+ powerUp.material.color.setHex(0xff0000);
677
+ powerUp.material.emissive.setHex(0x990000);
678
+ break;
679
+ }
680
+
681
+ powerUpGroup.add(powerUp);
682
+ powerUpGroup.position.set(x, y, z);
683
+ powerUpGroup.userData.speed = 0.05;
684
+
685
+ scene.add(powerUpGroup);
686
+ gameState.powerUps.push(powerUpGroup);
687
+
688
+ return powerUpGroup;
689
+ }
690
+
691
+ // 设置事件监听器
692
+ function setupEventListeners() {
693
+ // 鼠标移动
694
+ window.addEventListener('mousemove', (event) => {
695
+ mouse.x = (event.clientX / GAME.WIDTH) * 2 - 1;
696
+ mouse.y = -(event.clientY / GAME.HEIGHT) * 2 + 1;
697
+ });
698
+
699
+ // 鼠标按下
700
+ window.addEventListener('mousedown', () => {
701
+ isMouseDown = true;
702
+ document.getElementById('crosshair').classList.add('active');
703
+ });
704
+
705
+ // 鼠标释放
706
+ window.addEventListener('mouseup', () => {
707
+ isMouseDown = false;
708
+ document.getElementById('crosshair').classList.remove('active');
709
+ });
710
+
711
+ // 键盘按下
712
+ window.addEventListener('keydown', (event) => {
713
+ keys[event.code] = true;
714
+
715
+ // 空格键发射特殊武器
716
+ if (event.code === 'Space' && gameState.specialWeaponReady) {
717
+ fireSpecialWeapon();
718
+ }
719
+ });
720
+
721
+ // 键盘释放
722
+ window.addEventListener('keyup', (event) => {
723
+ keys[event.code] = false;
724
+ });
725
+
726
+ // 窗口大小调整
727
+ window.addEventListener('resize', () => {
728
+ GAME.WIDTH = window.innerWidth;
729
+ GAME.HEIGHT = window.innerHeight;
730
+ GAME.ASPECT = GAME.WIDTH / GAME.HEIGHT;
731
+
732
+ camera.aspect = GAME.ASPECT;
733
+ camera.updateProjectionMatrix();
734
+
735
+ renderer.setSize(GAME.WIDTH, GAME.HEIGHT);
736
+ });
737
+
738
+ // 开始按钮
739
+ document.getElementById('start-button').addEventListener('click', startGame);
740
+
741
+ // 重新开始按钮
742
+ document.getElementById('restart-button').addEventListener('click', restartGame);
743
+
744
+ // 下一关按钮
745
+ document.getElementById('next-level-button').addEventListener('click', nextLevel);
746
+ }
747
+
748
+ // 开始游戏
749
+ function startGame() {
750
+ document.getElementById('start-screen').style.display = 'none';
751
+ gameState = {
752
+ score: 0,
753
+ level: 1,
754
+ health: 100,
755
+ maxHealth: 100,
756
+ ammo: Infinity,
757
+ gameOver: false,
758
+ levelComplete: false,
759
+ enemies: [],
760
+ bullets: [],
761
+ enemyBullets: [],
762
+ powerUps: [],
763
+ activePowerUps: {},
764
+ boss: null,
765
+ bossActive: false,
766
+ enemiesSpawned: 0,
767
+ enemiesDestroyed: 0,
768
+ lastShot: 0,
769
+ shotDelay: 200,
770
+ lastEnemyShot: 0,
771
+ enemyShotDelay: 1000,
772
+ lastPowerUpSpawn: 0,
773
+ powerUpSpawnDelay: 15000,
774
+ specialWeaponReady: true,
775
+ specialWeaponCooldown: 10000,
776
+ lastSpecialWeaponUse: 0
777
+ };
778
+
779
+ updateUI();
780
+ spawnEnemies();
781
+ }
782
+
783
+ // 重新开始游戏
784
+ function restartGame() {
785
+ document.getElementById('game-over').style.display = 'none';
786
+
787
+ // 清除所有游戏对象
788
+ clearGameObjects();
789
+
790
+ // 重置玩家位置
791
+ playerGroup.position.set(0, 0, -10);
792
+
793
+ startGame();
794
+ }
795
+
796
+ // 下一关
797
+ function nextLevel() {
798
+ document.getElementById('level-complete').style.display = 'none';
799
+
800
+ // 清除所有游戏对象
801
+ clearGameObjects();
802
+
803
+ // 重置玩家位置
804
+ playerGroup.position.set(0, 0, -10);
805
+
806
+ // 增加关卡
807
+ gameState.level++;
808
+ gameState.enemiesSpawned = 0;
809
+ gameState.enemiesDestroyed = 0;
810
+ gameState.bossActive = false;
811
+ gameState.boss = null;
812
+
813
+ updateUI();
814
+ spawnEnemies();
815
+ }
816
+
817
+ // 清除所有游戏对象
818
+ function clearGameObjects() {
819
+ // 清除敌人
820
+ gameState.enemies.forEach(enemy => {
821
+ scene.remove(enemy);
822
+ });
823
+ gameState.enemies = [];
824
+
825
+ // 清除子弹
826
+ gameState.bullets.forEach(bullet => {
827
+ scene.remove(bullet);
828
+ });
829
+ gameState.bullets = [];
830
+
831
+ // 清除敌人子弹
832
+ gameState.enemyBullets.forEach(bullet => {
833
+ scene.remove(bullet);
834
+ });
835
+ gameState.enemyBullets = [];
836
+
837
+ // 清除能量道具
838
+ gameState.powerUps.forEach(powerUp => {
839
+ scene.remove(powerUp);
840
+ });
841
+ gameState.powerUps = [];
842
+
843
+ // 清除雷达标记
844
+ radarBlips.forEach(blip => {
845
+ if (blip.parentNode) {
846
+ blip.parentNode.removeChild(blip);
847
+ }
848
+ });
849
+ radarBlips = [];
850
+
851
+ // 隐藏Boss血条
852
+ document.getElementById('boss-health').style.display = 'none';
853
+ }
854
+
855
+ // 生成敌人
856
+ function spawnEnemies() {
857
+ const currentLevel = Math.min(gameState.level - 1, GAME.LEVELS.length - 1);
858
+ const levelData = GAME.LEVELS[currentLevel];
859
+
860
+ // 设置敌人生成间隔
861
+ const spawnInterval = setInterval(() => {
862
+ if (gameState.enemiesSpawned >= levelData.enemies) {
863
+ clearInterval(spawnInterval);
864
+
865
+ // 如果是Boss关卡且所有小敌人都被消灭,生成Boss
866
+ if (levelData.boss && gameState.enemiesDestroyed >= levelData.enemies && !gameState.bossActive) {
867
+ createBoss();
868
+ }
869
+ return;
870
+ }
871
+
872
+ // 随机生成敌人位置
873
+ const x = (Math.random() - 0.5) * 30;
874
+ const y = (Math.random() - 0.5) * 10;
875
+ const z = 50 + Math.random() * 50;
876
+
877
+ createEnemy(x, y, z, levelData.enemyHealth);
878
+ gameState.enemiesSpawned++;
879
+ updateUI();
880
+
881
+ }, levelData.spawnRate);
882
+ }
883
+
884
+ // 发射子弹
885
+ function fireBullet() {
886
+ const now = Date.now();
887
+ if (now - gameState.lastShot < gameState.shotDelay) return;
888
+
889
+ // 计算射击延迟(如果有火力增强道具)
890
+ const fireRatePower = gameState.activePowerUps['fireRate'];
891
+ const actualShotDelay = fireRatePower ? gameState.shotDelay * 0.5 : gameState.shotDelay;
892
+
893
+ if (now - gameState.lastShot < actualShotDelay) return;
894
+
895
+ gameState.lastShot = now;
896
+
897
+ // 从玩家位置发射子弹
898
+ const bullet = createBullet(
899
+ playerGroup.position.x,
900
+ playerGroup.position.y,
901
+ playerGroup.position.z + 1
902
+ );
903
+
904
+ // 设置子弹方向(朝向鼠标指向的位置)
905
+ raycaster.setFromCamera(mouse, camera);
906
+ const direction = raycaster.ray.direction.clone();
907
+ direction.multiplyScalar(100);
908
+
909
+ bullet.userData.direction = direction.normalize();
910
+
911
+ // 播放射击音效(这里可以添加音效)
912
+ }
913
+
914
+ // 发射特殊武器
915
+ function fireSpecialWeapon() {
916
+ const now = Date.now();
917
+ if (!gameState.specialWeaponReady || now - gameState.lastSpecialWeaponUse < gameState.specialWeaponCooldown) return;
918
+
919
+ gameState.specialWeaponReady = false;
920
+ gameState.lastSpecialWeaponUse = now;
921
+
922
+ // 创建多个子弹形成扇形攻击
923
+ const bulletCount = 10;
924
+ for (let i = 0; i < bulletCount; i++) {
925
+ setTimeout(() => {
926
+ const angle = (i / bulletCount) * Math.PI - Math.PI / 2;
927
+ const bullet = createBullet(
928
+ playerGroup.position.x,
929
+ playerGroup.position.y,
930
+ playerGroup.position.z + 1
931
+ );
932
+
933
+ // 设置子弹方向(扇形分布)
934
+ const direction = new THREE.Vector3(
935
+ Math.sin(angle) * 0.5,
936
+ 0,
937
+ 1
938
+ ).normalize();
939
+
940
+ bullet.userData.direction = direction;
941
+ bullet.userData.speed = GAME.BULLET_SPEED * 1.5;
942
+
943
+ // 特殊武器的子弹更大
944
+ bullet.children[0].scale.set(2, 2, 2);
945
+ }, i * 50);
946
+ }
947
+
948
+ // 启动特殊武器冷却计时器
949
+ setTimeout(() => {
950
+ gameState.specialWeaponReady = true;
951
+ }, gameState.specialWeaponCooldown);
952
+ }
953
+
954
+ // 敌人发射子弹
955
+ function enemyFireBullet(enemy) {
956
+ const now = Date.now();
957
+ if (now - enemy.userData.lastShot < enemy.userData.shotDelay) return;
958
+
959
+ enemy.userData.lastShot = now;
960
+
961
+ // 从敌人位置发射子弹
962
+ const bullet = createBullet(
963
+ enemy.position.x,
964
+ enemy.position.y,
965
+ enemy.position.z - 1,
966
+ true
967
+ );
968
+
969
+ // 设置子弹方向(朝向玩家)
970
+ const direction = new THREE.Vector3(
971
+ playerGroup.position.x - enemy.position.x,
972
+ playerGroup.position.y - enemy.position.y,
973
+ playerGroup.position.z - enemy.position.z
974
+ ).normalize();
975
+
976
+ bullet.userData.direction = direction;
977
+
978
+ // Boss发射更多的子弹
979
+ if (enemy.userData.isBoss) {
980
+ // 创建额外的子弹,形成扇形攻击
981
+ for (let i = 0; i < 3; i++) {
982
+ setTimeout(() => {
983
+ const angle = (i - 1) * 0.2;
984
+ const bullet = createBullet(
985
+ enemy.position.x,
986
+ enemy.position.y,
987
+ enemy.position.z - 1,
988
+ true
989
+ );
990
+
991
+ const dir = direction.clone();
992
+ dir.x += angle;
993
+ bullet.userData.direction = dir.normalize();
994
+ }, i * 100);
995
+ }
996
+ }
997
+ }
998
+
999
+ // 生成能量道具
1000
+ function spawnPowerUp() {
1001
+ const now = Date.now();
1002
+ if (now - gameState.lastPowerUpSpawn < gameState.powerUpSpawnDelay) return;
1003
+
1004
+ gameState.lastPowerUpSpawn = now;
1005
+
1006
+ // 随机生成道具位置
1007
+ const x = (Math.random() - 0.5) * 30;
1008
+ const y = (Math.random() - 0.5) * 10;
1009
+ const z = 30 + Math.random() * 40;
1010
+
1011
+ createPowerUp(x, y, z);
1012
+ }
1013
+
1014
+ // 更新UI
1015
+ function updateUI() {
1016
+ // 更新分数
1017
+ document.getElementById('score').textContent = `分数: ${gameState.score}`;
1018
+
1019
+ // 更新关卡
1020
+ document.getElementById('level').textContent = `关卡: ${gameState.level}`;
1021
+
1022
+ // 更新生命值
1023
+ const healthPercent = (gameState.health / gameState.maxHealth) * 100;
1024
+ document.getElementById('health-fill').style.width = `${healthPercent}%`;
1025
+
1026
+ // 更新弹药
1027
+ document.getElementById('ammo').textContent = `弹药: ${gameState.ammo === Infinity ? '∞' : gameState.ammo}`;
1028
+
1029
+ // 更新敌人数量
1030
+ const enemiesLeft = gameState.enemiesSpawned - gameState.enemiesDestroyed;
1031
+ document.getElementById('enemy-count').textContent = `敌人: ${enemiesLeft}`;
1032
+
1033
+ // 更新特殊武器状态
1034
+ const specialWeaponElement = document.getElementById('special-weapon');
1035
+ if (specialWeaponElement) {
1036
+ specialWeaponElement.style.opacity = gameState.specialWeaponReady ? '1' : '0.5';
1037
+ }
1038
+
1039
+ // 更新Boss血条
1040
+ if (gameState.bossActive && gameState.boss) {
1041
+ updateBossHealth();
1042
+ }
1043
+ }
1044
+
1045
+ // 更新Boss血条
1046
+ function updateBossHealth() {
1047
+ if (!gameState.boss || !gameState.bossActive) return;
1048
+
1049
+ const boss = gameState.boss.children[0];
1050
+ const healthPercent = (boss.userData.health / boss.userData.maxHealth) * 100;
1051
+ document.getElementById('boss-health-fill').style.width = `${healthPercent}%`;
1052
+ }
1053
+
1054
+ // 显示游戏结束
1055
+ function showGameOver() {
1056
+ document.getElementById('final-score').textContent = gameState.score;
1057
+ document.getElementById('final-level').textContent = gameState.level;
1058
+ document.getElementById('game-over').style.display = 'flex';
1059
+ gameState.gameOver = true;
1060
+ }
1061
+
1062
+ // 显示关卡完成
1063
+ function showLevelComplete() {
1064
+ document.getElementById('level-score').textContent = gameState.score;
1065
+ document.getElementById('next-level').textContent = gameState.level + 1;
1066
+ document.getElementById('level-complete').style.display = 'flex';
1067
+ gameState.levelComplete = true;
1068
+ }
1069
+
1070
+ // 应用能量道具效果
1071
+ function applyPowerUp(type) {
1072
+ // 如果已经有相同类型的道具,先清除之前的
1073
+ if (gameState.activePowerUps[type]) {
1074
+ clearTimeout(gameState.activePowerUps[type].timer);
1075
+ }
1076
+
1077
+ // 应用道具效果
1078
+ switch (type) {
1079
+ case 'health':
1080
+ gameState.health = Math.min(gameState.health + 30, gameState.maxHealth);
1081
+ updateUI();
1082
+ break;
1083
+
1084
+ case 'shield':
1085
+ // 护盾效果在碰撞检测中处理
1086
+ break;
1087
+
1088
+ case 'speed':
1089
+ // 速度效果在玩家移动中处理
1090
+ break;
1091
+
1092
+ case 'fireRate':
1093
+ // 射���速度效果在射击函数中处理
1094
+ break;
1095
+
1096
+ case 'special':
1097
+ gameState.specialWeaponReady = true;
1098
+ break;
1099
+ }
1100
+
1101
+ // 添加道具图标到UI
1102
+ addPowerUpIcon(type);
1103
+
1104
+ // 设置道具持续时间
1105
+ gameState.activePowerUps[type] = {
1106
+ active: true,
1107
+ timer: setTimeout(() => {
1108
+ removePowerUp(type);
1109
+ }, GAME.POWERUP_DURATION)
1110
+ };
1111
+ }
1112
+
1113
+ // 添加道具图标到UI
1114
+ function addPowerUpIcon(type) {
1115
+ const powerUpsContainer = document.getElementById('power-ups');
1116
+
1117
+ // 如果已经有相同类型的图标,先移除
1118
+ const existingIcon = document.getElementById(`power-up-${type}`);
1119
+ if (existingIcon) {
1120
+ powerUpsContainer.removeChild(existingIcon);
1121
+ }
1122
+
1123
+ const icon = document.createElement('div');
1124
+ icon.id = `power-up-${type}`;
1125
+ icon.className = 'power-up-icon';
1126
+
1127
+ // 根据类型设置图标
1128
+ switch (type) {
1129
+ case 'health':
1130
+ icon.innerHTML = '❤️';
1131
+ icon.style.backgroundColor = 'rgba(0, 255, 0, 0.3)';
1132
+ break;
1133
+ case 'shield':
1134
+ icon.innerHTML = '🛡️';
1135
+ icon.style.backgroundColor = 'rgba(0, 0, 255, 0.3)';
1136
+ break;
1137
+ case 'speed':
1138
+ icon.innerHTML = '⚡';
1139
+ icon.style.backgroundColor = 'rgba(255, 165, 0, 0.3)';
1140
+ break;
1141
+ case 'fireRate':
1142
+ icon.innerHTML = '🔥';
1143
+ icon.style.backgroundColor = 'rgba(255, 0, 255, 0.3)';
1144
+ break;
1145
+ case 'special':
1146
+ icon.innerHTML = '💣';
1147
+ icon.style.backgroundColor = 'rgba(255, 0, 0, 0.3)';
1148
+ break;
1149
+ }
1150
+
1151
+ powerUpsContainer.appendChild(icon);
1152
+
1153
+ // 添加动画效果
1154
+ icon.style.transform = 'scale(0)';
1155
+ setTimeout(() => {
1156
+ icon.style.transform = 'scale(1)';
1157
+ icon.style.transition = 'transform 0.3s';
1158
+ }, 10);
1159
+ }
1160
+
1161
+ // 移除能量道具效果
1162
+ function removePowerUp(type) {
1163
+ if (!gameState.activePowerUps[type]) return;
1164
+
1165
+ gameState.activePowerUps[type].active = false;
1166
+ delete gameState.activePowerUps[type];
1167
+
1168
+ // 从UI中移除图标
1169
+ const icon = document.getElementById(`power-up-${type}`);
1170
+ if (icon) {
1171
+ icon.style.transform = 'scale(0)';
1172
+ setTimeout(() => {
1173
+ if (icon.parentNode) {
1174
+ icon.parentNode.removeChild(icon);
1175
+ }
1176
+ }, 300);
1177
+ }
1178
+ }
1179
+
1180
+ // 更新雷达
1181
+ function updateRadar() {
1182
+ // 清除旧的雷达标记
1183
+ radarBlips.forEach(blip => {
1184
+ if (blip.parentNode) {
1185
+ blip.parentNode.removeChild(blip);
1186
+ }
1187
+ });
1188
+ radarBlips = [];
1189
+
1190
+ // 添加玩家标记
1191
+ const playerBlip = document.createElement('div');
1192
+ playerBlip.className = 'radar-blip';
1193
+ playerBlip.style.backgroundColor = '#00ffff';
1194
+ playerBlip.style.left = '50%';
1195
+ playerBlip.style.top = '50%';
1196
+ document.getElementById('radar').appendChild(playerBlip);
1197
+ radarBlips.push(playerBlip);
1198
+
1199
+ // 添加敌人标记
1200
+ gameState.enemies.forEach(enemy => {
1201
+ // 计算敌人相对于玩家的位置
1202
+ const relativeX = enemy.position.x - playerGroup.position.x;
1203
+ const relativeZ = enemy.position.z - playerGroup.position.z;
1204
+
1205
+ // 限制在雷达范围内
1206
+ const maxDistance = 50;
1207
+ const distance = Math.min(Math.sqrt(relativeX * relativeX + relativeZ * relativeZ), maxDistance);
1208
+ const angle = Math.atan2(relativeX, relativeZ);
1209
+
1210
+ // 转换为雷达坐标
1211
+ const radarX = 50 + (distance / maxDistance) * 50 * Math.sin(angle);
1212
+ const radarY = 50 - (distance / maxDistance) * 50 * Math.cos(angle);
1213
+
1214
+ // 创建雷达标记
1215
+ const blip = document.createElement('div');
1216
+ blip.className = 'radar-blip';
1217
+ blip.style.left = `${radarX}%`;
1218
+ blip.style.top = `${radarY}%`;
1219
+
1220
+ // Boss标记更大
1221
+ if (enemy.userData.isBoss) {
1222
+ blip.style.width = '10px';
1223
+ blip.style.height = '10px';
1224
+ }
1225
+
1226
+ document.getElementById('radar').appendChild(blip);
1227
+ radarBlips.push(blip);
1228
+ });
1229
+ }
1230
+
1231
+ // 游戏主循环
1232
+ function animate() {
1233
+ requestAnimationFrame(animate);
1234
+
1235
+ const delta = clock.getDelta();
1236
+ const time = clock.getElapsedTime();
1237
+
1238
+ // 如果游戏结束或关卡完成,不更新游戏状态
1239
+ if (gameState.gameOver || gameState.levelComplete) {
1240
+ effect.render(scene, camera);
1241
+ return;
1242
+ }
1243
+
1244
+ // 玩家移动
1245
+ const speedPower = gameState.activePowerUps['speed'];
1246
+ const actualPlayerSpeed = speedPower ? GAME.PLAYER_SPEED * 1.5 : GAME.PLAYER_SPEED;
1247
+
1248
+ if (keys['KeyW']) playerGroup.position.z += actualPlayerSpeed;
1249
+ if (keys['KeyS']) playerGroup.position.z -= actualPlayerSpeed;
1250
+ if (keys['KeyA']) playerGroup.position.x -= actualPlayerSpeed;
1251
+ if (keys['KeyD']) playerGroup.position.x += actualPlayerSpeed;
1252
+ if (keys['Space']) playerGroup.position.y += actualPlayerSpeed;
1253
+ if (keys['ShiftLeft']) playerGroup.position.y -= actualPlayerSpeed;
1254
+
1255
+ // 限制玩家移动范围
1256
+ playerGroup.position.x = Math.max(-15, Math.min(15, playerGroup.position.x));
1257
+ playerGroup.position.y = Math.max(-5, Math.min(5, playerGroup.position.y));
1258
+ playerGroup.position.z = Math.max(-15, Math.min(40, playerGroup.position.z));
1259
+
1260
+ // 鼠标射击
1261
+ if (isMouseDown) {
1262
+ fireBullet();
1263
+ }
1264
+
1265
+ // 生成能量道具
1266
+ spawnPowerUp();
1267
+
1268
+ // 更新子弹
1269
+ updateBullets(delta);
1270
+
1271
+ // 更新敌人
1272
+ updateEnemies(delta, time);
1273
+
1274
+ // 更新能量道具
1275
+ updatePowerUps(delta);
1276
+
1277
+ // 检测碰撞
1278
+ checkCollisions();
1279
+
1280
+ // 更新雷达
1281
+ updateRadar();
1282
+
1283
+ // 更新UI
1284
+ updateUI();
1285
+
1286
+ // 渲染场景
1287
+ effect.render(scene, camera);
1288
+ }
1289
+
1290
+ // 更新子弹
1291
+ function updateBullets(delta) {
1292
+ // 玩家子弹
1293
+ for (let i = gameState.bullets.length - 1; i >= 0; i--) {
1294
+ const bullet = gameState.bullets[i];
1295
+
1296
+ // 移动子弹
1297
+ bullet.position.x += bullet.userData.direction.x * bullet.userData.speed * 60 * delta;
1298
+ bullet.position.y += bullet.userData.direction.y * bullet.userData.speed * 60 * delta;
1299
+ bullet.position.z += bullet.userData.direction.z * bullet.userData.speed * 60 * delta;
1300
+
1301
+ // 移除超出范围的子弹
1302
+ if (bullet.position.z > 100 ||
1303
+ bullet.position.z < -50 ||
1304
+ bullet.position.x < -50 ||
1305
+ bullet.position.x > 50 ||
1306
+ bullet.position.y < -20 ||
1307
+ bullet.position.y > 20) {
1308
+ scene.remove(bullet);
1309
+ gameState.bullets.splice(i, 1);
1310
+ }
1311
+ }
1312
+
1313
+ // 敌人子弹
1314
+ for (let i = gameState.enemyBullets.length - 1; i >= 0; i--) {
1315
+ const bullet = gameState.enemyBullets[i];
1316
+
1317
+ // 移动子弹
1318
+ bullet.position.x += bullet.userData.direction.x * bullet.userData.speed * 60 * delta;
1319
+ bullet.position.y += bullet.userData.direction.y * bullet.userData.speed * 60 * delta;
1320
+ bullet.position.z += bullet.userData.direction.z * bullet.userData.speed * 60 * delta;
1321
+
1322
+ // 移除超出范围的子弹
1323
+ if (bullet.position.z > 100 ||
1324
+ bullet.position.z < -50 ||
1325
+ bullet.position.x < -50 ||
1326
+ bullet.position.x > 50 ||
1327
+ bullet.position.y < -20 ||
1328
+ bullet.position.y > 20) {
1329
+ scene.remove(bullet);
1330
+ gameState.enemyBullets.splice(i, 1);
1331
+ }
1332
+ }
1333
+ }
1334
+
1335
+ // 更新敌人
1336
+ function updateEnemies(delta, time) {
1337
+ const currentLevel = Math.min(gameState.level - 1, GAME.LEVELS.length - 1);
1338
+ const levelData = GAME.LEVELS[currentLevel];
1339
+
1340
+ for (let i = gameState.enemies.length - 1; i >= 0; i--) {
1341
+ const enemy = gameState.enemies[i];
1342
+
1343
+ // Boss行为
1344
+ if (enemy.userData.isBoss) {
1345
+ // Boss移动模式
1346
+ const bossMovePattern = time * 0.5;
1347
+ enemy.position.x = Math.sin(bossMovePattern) * 10;
1348
+ enemy.position.y = Math.cos(bossMovePattern * 0.7) * 3;
1349
+
1350
+ // Boss射击
1351
+ if (time - enemy.userData.lastShot > enemy.userData.shotDelay) {
1352
+ enemyFireBullet(enemy);
1353
+ }
1354
+ } else {
1355
+ // 普通敌人移动
1356
+ enemy.position.z -= enemy.userData.speed * 60 * delta;
1357
+
1358
+ // 敌人射击
1359
+ if (Math.random() < 0.01 && time - gameState.lastEnemyShot > levelData.spawnRate * 2) {
1360
+ gameState.lastEnemyShot = time;
1361
+ enemyFireBullet(enemy);
1362
+ }
1363
+ }
1364
+
1365
+ // 移除超出范围的敌人
1366
+ if (enemy.position.z < -30) {
1367
+ scene.remove(enemy);
1368
+ gameState.enemies.splice(i, 1);
1369
+
1370
+ // 如果敌人超出范围,减少生命值
1371
+ if (!enemy.userData.isBoss) {
1372
+ gameState.health -= 5;
1373
+ if (gameState.health <= 0) {
1374
+ gameState.health = 0;
1375
+ showGameOver();
1376
+ }
1377
+ updateUI();
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ // 检查关卡是否完成
1383
+ if (!gameState.bossActive &&
1384
+ gameState.enemiesSpawned >= levelData.enemies &&
1385
+ gameState.enemiesDestroyed >= levelData.enemies) {
1386
+
1387
+ // 如果是最后一关,游戏胜利
1388
+ if (gameState.level >= GAME.LEVELS.length) {
1389
+ showGameOver(); // 这里可以改为显示胜利画面
1390
+ } else {
1391
+ showLevelComplete();
1392
+ }
1393
+ }
1394
+ }
1395
+
1396
+ // 更新能量道具
1397
+ function updatePowerUps(delta) {
1398
+ for (let i = gameState.powerUps.length - 1; i >= 0; i--) {
1399
+ const powerUp = gameState.powerUps[i];
1400
+
1401
+ // 旋转道具
1402
+ powerUp.rotation.x += 0.05 * 60 * delta;
1403
+ powerUp.rotation.y += 0.05 * 60 * delta;
1404
+
1405
+ // 上下浮动
1406
+ powerUp.position.y += Math.sin(clock.getElapsedTime() * 3) * 0.01 * 60 * delta;
1407
+
1408
+ // 向玩家移动
1409
+ const direction = new THREE.Vector3(
1410
+ playerGroup.position.x - powerUp.position.x,
1411
+ playerGroup.position.y - powerUp.position.y,
1412
+ playerGroup.position.z - powerUp.position.z
1413
+ ).normalize();
1414
+
1415
+ powerUp.position.x += direction.x * powerUp.userData.speed * 60 * delta;
1416
+ powerUp.position.y += direction.y * powerUp.userData.speed * 60 * delta;
1417
+ powerUp.position.z += direction.z * powerUp.userData.speed * 60 * delta;
1418
+
1419
+ // 移除超出范围的子弹
1420
+ if (powerUp.position.z > 100 ||
1421
+ powerUp.position.z < -50 ||
1422
+ powerUp.position.x < -50 ||
1423
+ powerUp.position.x > 50 ||
1424
+ powerUp.position.y < -20 ||
1425
+ powerUp.position.y > 20) {
1426
+ scene.remove(powerUp);
1427
+ gameState.powerUps.splice(i, 1);
1428
+ }
1429
+ }
1430
+ }
1431
+
1432
+ // 检测碰撞
1433
+ function checkCollisions() {
1434
+ // 玩家子弹与敌人碰撞
1435
+ for (let i = gameState.bullets.length - 1; i >= 0; i--) {
1436
+ const bullet = gameState.bullets[i];
1437
+
1438
+ for (let j = gameState.enemies.length - 1; j >= 0; j--) {
1439
+ const enemy = gameState.enemies[j];
1440
+ const enemyMesh = enemy.children[0];
1441
+
1442
+ // 简单的距离检测碰撞
1443
+ const distance = bullet.position.distanceTo(enemyMesh.position);
1444
+ if (distance < enemyMesh.geometry.boundingSphere.radius + 0.2) {
1445
+ // 敌人受伤
1446
+ enemyMesh.userData.health--;
1447
+
1448
+ // 根据敌人血量改变颜色
1449
+ const healthPercent = enemyMesh.userData.health / enemyMesh.userData.maxHealth;
1450
+ if (healthPercent < 0.33) {
1451
+ enemyMesh.material.color.setHex(0xff0000);
1452
+ enemyMesh.material.emissive.setHex(0x990000);
1453
+ } else if (healthPercent < 0.66) {
1454
+ enemyMesh.material.color.setHex(0xff9900);
1455
+ enemyMesh.material.emissive.setHex(0x994400);
1456
+ }
1457
+
1458
+ // 移除子弹
1459
+ scene.remove(bullet);
1460
+ gameState.bullets.splice(i, 1);
1461
+
1462
+ // 如果敌人死亡
1463
+ if (enemyMesh.userData.health <= 0) {
1464
+ // 增加分数
1465
+ const points = enemy.userData.isBoss ? 500 : 100 * gameState.level;
1466
+ gameState.score += points;
1467
+
1468
+ // 随机掉落能量道具
1469
+ if (Math.random() < 0.3 || enemy.userData.isBoss) {
1470
+ createPowerUp(enemy.position.x, enemy.position.y, enemy.position.z);
1471
+ }
1472
+
1473
+ // 移除敌人
1474
+ scene.remove(enemy);
1475
+ gameState.enemies.splice(j, 1);
1476
+ gameState.enemiesDestroyed++;
1477
+
1478
+ // 如果是Boss
1479
+ if (enemy.userData.isBoss) {
1480
+ gameState.bossActive = false;
1481
+ gameState.boss = null;
1482
+ document.getElementById('boss-health').style.display = 'none';
1483
+ }
1484
+ }
1485
+
1486
+ break;
1487
+ }
1488
+ }
1489
+ }
1490
+
1491
+ // 敌人子弹与玩家碰撞
1492
+ for (let i = gameState.enemyBullets.length - 1; i >= 0; i--) {
1493
+ const bullet = gameState.enemyBullets[i];
1494
+
1495
+ // 简单的距离检测碰撞
1496
+ const distance = bullet.position.distanceTo(playerGroup.position);
1497
+ if (distance < 1) {
1498
+ // 如果有护盾,不受伤
1499
+ if (!gameState.activePowerUps['shield']) {
1500
+ gameState.health -= 10;
1501
+
1502
+ if (gameState.health <= 0) {
1503
+ gameState.health = 0;
1504
+ showGameOver();
1505
+ }
1506
+ }
1507
+
1508
+ // 移除子弹
1509
+ scene.remove(bullet);
1510
+ gameState.enemyBullets.splice(i, 1);
1511
+ }
1512
+ }
1513
+
1514
+ // 能量道具与玩家碰撞
1515
+ for (let i = gameState.powerUps.length - 1; i >= 0; i--) {
1516
+ const powerUp = gameState.powerUps[i];
1517
+
1518
+ // 简单的距离检测碰撞
1519
+ const distance = powerUp.position.distanceTo(playerGroup.position);
1520
+ if (distance < 1) {
1521
+ // 应用道具效果
1522
+ applyPowerUp(powerUp.children[0].userData.type);
1523
+
1524
+ // 移除道具
1525
+ scene.remove(powerUp);
1526
+ gameState.powerUps.splice(i, 1);
1527
+ }
1528
+ }
1529
+
1530
+ // 敌人与玩家碰撞
1531
+ for (let i = gameState.enemies.length - 1; i >= 0; i--) {
1532
+ const enemy = gameState.enemies[i];
1533
+ const enemyMesh = enemy.children[0];
1534
+
1535
+ // 简单的距离检测碰撞
1536
+ const distance = enemyMesh.position.distanceTo(playerGroup.position);
1537
+ if (distance < enemyMesh.geometry.boundingSphere.radius + 0.5) {
1538
+ // 如果有护盾,不受伤
1539
+ if (!gameState.activePowerUps['shield']) {
1540
+ gameState.health -= 20;
1541
+
1542
+ if (gameState.health <= 0) {
1543
+ gameState.health = 0;
1544
+ showGameOver();
1545
+ }
1546
+ }
1547
+
1548
+ // 敌人受伤
1549
+ enemyMesh.userData.health -= 5;
1550
+
1551
+ // 如果敌人死亡
1552
+ if (enemyMesh.userData.health <= 0) {
1553
+ // 增加分数
1554
+ const points = enemy.userData.isBoss ? 500 : 100 * gameState.level;
1555
+ gameState.score += points;
1556
+
1557
+ // 随机掉落能量道具
1558
+ if (Math.random() < 0.3 || enemy.userData.isBoss) {
1559
+ createPowerUp(enemy.position.x, enemy.position.y, enemy.position.z);
1560
+ }
1561
+
1562
+ // 移除敌人
1563
+ scene.remove(enemy);
1564
+ gameState.enemies.splice(i, 1);
1565
+ gameState.enemiesDestroyed++;
1566
+
1567
+ // 如果是Boss
1568
+ if (enemy.userData.isBoss) {
1569
+ gameState.bossActive = false;
1570
+ gameState.boss = null;
1571
+ document.getElementById('boss-health').style.display = 'none';
1572
+ }
1573
+ }
1574
+
1575
+ break;
1576
+ }
1577
+ }
1578
+ }
1579
+
1580
+ // 启动游戏
1581
+ init();
1582
+ </script>
1583
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=CYXiaofeng/fly-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1584
+ </html>