af2022 commited on
Commit
bdc0272
·
verified ·
1 Parent(s): de35751

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +642 -19
index.html CHANGED
@@ -1,19 +1,642 @@
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>Aleste 2 Clone</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ body {
10
+ margin: 0;
11
+ overflow: hidden;
12
+ background-color: #000;
13
+ font-family: 'Courier New', monospace;
14
+ }
15
+ canvas {
16
+ display: block;
17
+ width: 100vw;
18
+ height: 100vh;
19
+ }
20
+ #ui {
21
+ position: absolute;
22
+ top: 10px;
23
+ left: 10px;
24
+ color: #00FFFF;
25
+ font-size: 18px;
26
+ text-shadow: 0 0 10px #00FFFF, 0 0 20px #0066FF;
27
+ background: rgba(0, 0, 0, 0.5);
28
+ padding: 10px;
29
+ border-radius: 5px;
30
+ border: 1px solid #00FFFF;
31
+ }
32
+ #gameOver {
33
+ position: absolute;
34
+ top: 50%;
35
+ left: 50%;
36
+ transform: translate(-50%, -50%);
37
+ color: #FF0000;
38
+ font-size: 48px;
39
+ text-align: center;
40
+ text-shadow: 0 0 10px #FF0000, 0 0 20px #990000;
41
+ display: none;
42
+ background: rgba(0, 0, 0, 0.7);
43
+ padding: 20px 40px;
44
+ border-radius: 10px;
45
+ border: 2px solid #FF0000;
46
+ }
47
+ #loading {
48
+ position: absolute;
49
+ top: 50%;
50
+ left: 50%;
51
+ transform: translate(-50%, -50%);
52
+ color: #00FFFF;
53
+ font-size: 24px;
54
+ text-align: center;
55
+ text-shadow: 0 0 10px #00FFFF;
56
+ background: rgba(0, 0, 0, 0.7);
57
+ padding: 20px;
58
+ border-radius: 10px;
59
+ border: 1px solid #00FFFF;
60
+ }
61
+ #musicControls {
62
+ position: absolute;
63
+ bottom: 20px;
64
+ right: 20px;
65
+ display: flex;
66
+ gap: 10px;
67
+ }
68
+ .music-btn {
69
+ background: rgba(0, 0, 0, 0.7);
70
+ color: #00FFFF;
71
+ border: 1px solid #00FFFF;
72
+ border-radius: 4px;
73
+ padding: 8px 12px;
74
+ cursor: pointer;
75
+ transition: all 0.3s;
76
+ text-shadow: 0 0 5px #00FFFF;
77
+ }
78
+ .music-btn:hover {
79
+ background: rgba(0, 255, 255, 0.3);
80
+ box-shadow: 0 0 10px #00FFFF;
81
+ }
82
+ #powerBar {
83
+ position: absolute;
84
+ bottom: 20px;
85
+ left: 20px;
86
+ width: 200px;
87
+ height: 20px;
88
+ background: rgba(0, 0, 0, 0.5);
89
+ border: 1px solid #00FFFF;
90
+ border-radius: 3px;
91
+ overflow: hidden;
92
+ }
93
+ #powerFill {
94
+ height: 100%;
95
+ width: 0%;
96
+ background: linear-gradient(90deg, #00FFFF, #0066FF);
97
+ transition: width 0.3s;
98
+ }
99
+ #powerLabel {
100
+ position: absolute;
101
+ top: -20px;
102
+ left: 0;
103
+ color: #00FFFF;
104
+ font-size: 14px;
105
+ }
106
+ .glow {
107
+ text-shadow: 0 0 5px currentColor;
108
+ }
109
+ @keyframes pulse {
110
+ 0% { opacity: 0.7; }
111
+ 50% { opacity: 1; }
112
+ 100% { opacity: 0.7; }
113
+ }
114
+ .pulse {
115
+ animation: pulse 2s infinite;
116
+ }
117
+ </style>
118
+ </head>
119
+ <body>
120
+ <div id="ui">
121
+ <div>SCORE: <span id="score" class="glow">0</span></div>
122
+ <div>WEAPON: <span id="weapon" class="glow">NORMAL</span></div>
123
+ <div>FPS: <span id="fps" class="glow">0</span></div>
124
+ </div>
125
+
126
+ <div id="powerBar">
127
+ <div id="powerLabel">POWER</div>
128
+ <div id="powerFill"></div>
129
+ </div>
130
+
131
+ <div id="gameOver">
132
+ GAME OVER<br>
133
+ <span style="font-size: 24px;">Press R to restart</span>
134
+ </div>
135
+
136
+ <div id="loading" class="pulse">
137
+ <div>Loading game assets...</div>
138
+ <div style="font-size: 14px; margin-top: 10px;">Aleste 2 Clone</div>
139
+ </div>
140
+
141
+ <div id="musicControls">
142
+ <button id="playMusic" class="music-btn">▶ Play Music</button>
143
+ <button id="stopMusic" class="music-btn">■ Stop Music</button>
144
+ </div>
145
+
146
+ <canvas id="gameCanvas"></canvas>
147
+
148
+ <audio id="bgMusic" loop>
149
+ <source src="https://www.msx.org/sites/default/files/downloads/music/mp3/Meits_Aleste2Area1.mp3" type="audio/mpeg">
150
+ </audio>
151
+
152
+ <script>
153
+ // Game constants
154
+ const PLAYER_SIZE = 20;
155
+ const PROJECTILE_WIDTH = 4;
156
+ const PROJECTILE_HEIGHT = 12;
157
+ const ENEMY_SIZE = 24;
158
+ const SCROLL_SPEED = 2;
159
+ const BG_LINE_SPACING = 40;
160
+
161
+ // Game state
162
+ let gameRunning = true;
163
+ let score = 0;
164
+ let weaponType = 'normal'; // 'normal' or 'power'
165
+ let powerLevel = 0;
166
+ let assetsLoaded = false;
167
+ let lastTime = 0;
168
+ let fps = 0;
169
+ let frameCount = 0;
170
+ let lastFpsUpdate = 0;
171
+
172
+ // Canvas setup
173
+ const canvas = document.getElementById('gameCanvas');
174
+ const ctx = canvas.getContext('2d');
175
+ canvas.width = window.innerWidth;
176
+ canvas.height = window.innerHeight;
177
+
178
+ // Audio elements
179
+ const bgMusic = document.getElementById('bgMusic');
180
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
181
+
182
+ // Player object
183
+ const player = {
184
+ x: canvas.width / 2,
185
+ y: canvas.height - 60,
186
+ width: PLAYER_SIZE,
187
+ height: PLAYER_SIZE,
188
+ speed: 5,
189
+ color: '#00FFFF',
190
+ projectiles: [],
191
+ shootCooldown: 0,
192
+
193
+ update: function() {
194
+ // Movement
195
+ if (keys.ArrowLeft && this.x > 0) this.x -= this.speed;
196
+ if (keys.ArrowRight && this.x < canvas.width - this.width) this.x += this.speed;
197
+ if (keys.ArrowUp && this.y > 0) this.y -= this.speed;
198
+ if (keys.ArrowDown && this.y < canvas.height - this.height) this.y += this.speed;
199
+
200
+ // Shooting cooldown
201
+ if (this.shootCooldown > 0) this.shootCooldown--;
202
+
203
+ // Shoot when space is pressed and cooldown is 0
204
+ if (keys[' '] && this.shootCooldown === 0) {
205
+ this.shoot();
206
+ this.shootCooldown = weaponType === 'normal' ? 10 : 20;
207
+
208
+ // Increase power level when shooting
209
+ if (powerLevel < 100) {
210
+ powerLevel += 1;
211
+ document.getElementById('powerFill').style.width = powerLevel + '%';
212
+
213
+ // Check if weapon should upgrade
214
+ if (powerLevel >= 100 && weaponType === 'normal') {
215
+ weaponType = 'power';
216
+ document.getElementById('weapon').textContent = 'POWER';
217
+ playSound('powerUp');
218
+ }
219
+ }
220
+ }
221
+
222
+ // Update projectiles
223
+ for (let i = this.projectiles.length - 1; i >= 0; i--) {
224
+ this.projectiles[i].update();
225
+
226
+ // Remove projectiles that are off screen
227
+ if (this.projectiles[i].y + this.projectiles[i].height < 0) {
228
+ this.projectiles.splice(i, 1);
229
+ }
230
+ }
231
+ },
232
+
233
+ shoot: function() {
234
+ playSound('shoot');
235
+ const projectile = {
236
+ x: this.x + this.width / 2 - PROJECTILE_WIDTH / 2,
237
+ y: this.y,
238
+ width: PROJECTILE_WIDTH,
239
+ height: PROJECTILE_HEIGHT,
240
+ speed: weaponType === 'normal' ? 10 : 5,
241
+ damage: weaponType === 'normal' ? 1 : 3,
242
+ color: weaponType === 'normal' ? '#FF0000' : '#FFFF00',
243
+
244
+ update: function() {
245
+ this.y -= this.speed;
246
+ },
247
+
248
+ draw: function() {
249
+ ctx.fillStyle = this.color;
250
+ ctx.fillRect(this.x, this.y, this.width, this.height);
251
+
252
+ // Add a glow effect for power shots
253
+ if (weaponType === 'power') {
254
+ ctx.fillStyle = 'rgba(255, 255, 0, 0.3)';
255
+ ctx.fillRect(this.x - 2, this.y - 2, this.width + 4, this.height + 4);
256
+ }
257
+ }
258
+ };
259
+
260
+ this.projectiles.push(projectile);
261
+
262
+ // Add additional projectiles for power weapon
263
+ if (weaponType === 'power') {
264
+ const leftProjectile = {...projectile};
265
+ leftProjectile.x -= 15;
266
+ this.projectiles.push(leftProjectile);
267
+
268
+ const rightProjectile = {...projectile};
269
+ rightProjectile.x += 15;
270
+ this.projectiles.push(rightProjectile);
271
+ }
272
+ },
273
+
274
+ draw: function() {
275
+ // Draw ship body
276
+ ctx.fillStyle = this.color;
277
+ ctx.fillRect(this.x, this.y, this.width, this.height);
278
+
279
+ // Draw ship details
280
+ ctx.fillStyle = '#FFFFFF';
281
+ ctx.fillRect(this.x + 5, this.y + 5, 2, 2);
282
+ ctx.fillRect(this.x + this.width - 7, this.y + 5, 2, 2);
283
+
284
+ // Draw engine glow
285
+ const gradient = ctx.createLinearGradient(
286
+ this.x + 5, this.y + this.height,
287
+ this.x + this.width - 5, this.y + this.height
288
+ );
289
+ gradient.addColorStop(0, 'rgba(0, 255, 255, 0)');
290
+ gradient.addColorStop(0.5, 'rgba(0, 255, 255, 0.8)');
291
+ gradient.addColorStop(1, 'rgba(0, 255, 255, 0)');
292
+
293
+ ctx.fillStyle = gradient;
294
+ ctx.fillRect(this.x + 5, this.y + this.height, this.width - 10, 10);
295
+
296
+ // Draw projectiles
297
+ this.projectiles.forEach(projectile => projectile.draw());
298
+ }
299
+ };
300
+
301
+ // Enemies array
302
+ let enemies = [];
303
+
304
+ // Enemy spawner
305
+ function spawnEnemy() {
306
+ const enemyTypes = [
307
+ { health: 1, speed: 1 + Math.random() * 3, color: `hsl(${Math.random() * 60 + 300}, 70%, 50%)` },
308
+ { health: 2, speed: 0.5 + Math.random() * 2, color: `hsl(${Math.random() * 60 + 180}, 70%, 50%)` },
309
+ { health: 3, speed: 0.3 + Math.random() * 1.5, color: `hsl(${Math.random() * 60 + 60}, 70%, 50%)` }
310
+ ];
311
+
312
+ const type = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
313
+
314
+ const enemy = {
315
+ x: Math.random() * (canvas.width - ENEMY_SIZE),
316
+ y: -ENEMY_SIZE,
317
+ width: ENEMY_SIZE,
318
+ height: ENEMY_SIZE,
319
+ speed: type.speed,
320
+ health: type.health,
321
+ color: type.color,
322
+ hitFlash: 0,
323
+
324
+ update: function() {
325
+ this.y += this.speed;
326
+
327
+ // Reduce hit flash timer
328
+ if (this.hitFlash > 0) {
329
+ this.hitFlash--;
330
+ }
331
+
332
+ // Check collision with player
333
+ if (checkCollision(this, player)) {
334
+ gameOver();
335
+ }
336
+
337
+ // Check collision with projectiles
338
+ for (let i = player.projectiles.length - 1; i >= 0; i--) {
339
+ if (checkCollision(this, player.projectiles[i])) {
340
+ this.health -= player.projectiles[i].damage;
341
+ player.projectiles.splice(i, 1);
342
+ this.hitFlash = 5;
343
+ playSound('hit');
344
+
345
+ if (this.health <= 0) {
346
+ score += 10 * type.health;
347
+ document.getElementById('score').textContent = score;
348
+ return false; // Mark for removal
349
+ }
350
+ }
351
+ }
352
+
353
+ return true; // Keep enemy
354
+ },
355
+
356
+ draw: function() {
357
+ // Draw enemy body with flash effect if hit
358
+ const flashColor = this.hitFlash > 0 ? '#FFFFFF' : this.color;
359
+ ctx.fillStyle = flashColor;
360
+ ctx.fillRect(this.x, this.y, this.width, this.height);
361
+
362
+ // Draw enemy details
363
+ ctx.fillStyle = '#000000';
364
+ ctx.fillRect(this.x + 8, this.y + 8, 8, 8);
365
+
366
+ // Draw health indicator for tougher enemies
367
+ if (type.health > 1) {
368
+ ctx.fillStyle = '#FFFFFF';
369
+ ctx.font = '10px Courier New';
370
+ ctx.fillText(`${this.health}`, this.x + 12, this.y + 15);
371
+ }
372
+ }
373
+ };
374
+
375
+ enemies.push(enemy);
376
+ }
377
+
378
+ // Background state
379
+ let bgOffset = 0;
380
+
381
+ // Input handling
382
+ const keys = {};
383
+ document.addEventListener('keydown', e => {
384
+ keys[e.key] = true;
385
+
386
+ // Toggle weapon with Q
387
+ if (e.key === 'q' && powerLevel >= 100) {
388
+ weaponType = weaponType === 'normal' ? 'power' : 'normal';
389
+ document.getElementById('weapon').textContent = weaponType.toUpperCase();
390
+ playSound('weaponSwitch');
391
+ }
392
+
393
+ // Restart game with R when game over
394
+ if (!gameRunning && e.key.toLowerCase() === 'r') {
395
+ resetGame();
396
+ }
397
+ });
398
+
399
+ document.addEventListener('keyup', e => {
400
+ keys[e.key] = false;
401
+ });
402
+
403
+ // Collision detection
404
+ function checkCollision(obj1, obj2) {
405
+ return obj1.x < obj2.x + obj2.width &&
406
+ obj1.x + obj1.width > obj2.x &&
407
+ obj1.y < obj2.y + obj2.height &&
408
+ obj1.y + obj1.height > obj2.y;
409
+ }
410
+
411
+ // Game over function
412
+ function gameOver() {
413
+ gameRunning = false;
414
+ document.getElementById('gameOver').style.display = 'block';
415
+ playSound('gameOver');
416
+ bgMusic.pause();
417
+ }
418
+
419
+ // Reset game function
420
+ function resetGame() {
421
+ gameRunning = true;
422
+ score = 0;
423
+ powerLevel = 0;
424
+ weaponType = 'normal';
425
+ player.x = canvas.width / 2;
426
+ player.y = canvas.height - 60;
427
+ player.projectiles = [];
428
+ enemies = [];
429
+ document.getElementById('score').textContent = '0';
430
+ document.getElementById('weapon').textContent = 'NORMAL';
431
+ document.getElementById('powerFill').style.width = '0%';
432
+ document.getElementById('gameOver').style.display = 'none';
433
+
434
+ // Start music again
435
+ bgMusic.currentTime = 0;
436
+ bgMusic.play();
437
+
438
+ // Spawn initial enemies
439
+ for (let i = 0; i < 5; i++) {
440
+ setTimeout(spawnEnemy, i * 1000);
441
+ }
442
+ }
443
+
444
+ // Sound effects
445
+ function playSound(type) {
446
+ const oscillator = audioContext.createOscillator();
447
+ const gainNode = audioContext.createGain();
448
+
449
+ oscillator.connect(gainNode);
450
+ gainNode.connect(audioContext.destination);
451
+
452
+ switch (type) {
453
+ case 'shoot':
454
+ oscillator.type = 'square';
455
+ oscillator.frequency.value = 880;
456
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
457
+ oscillator.start();
458
+ oscillator.stop(audioContext.currentTime + 0.1);
459
+ break;
460
+
461
+ case 'hit':
462
+ oscillator.type = 'sine';
463
+ oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
464
+ oscillator.frequency.exponentialRampToValueAtTime(110, audioContext.currentTime + 0.2);
465
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.2);
466
+ oscillator.start();
467
+ oscillator.stop(audioContext.currentTime + 0.2);
468
+ break;
469
+
470
+ case 'gameOver':
471
+ oscillator.type = 'sawtooth';
472
+ oscillator.frequency.value = 110;
473
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
474
+ oscillator.start();
475
+ oscillator.stop(audioContext.currentTime + 0.5);
476
+ break;
477
+
478
+ case 'powerUp':
479
+ oscillator.type = 'sine';
480
+ oscillator.frequency.setValueAtTime(220, audioContext.currentTime);
481
+ oscillator.frequency.exponentialRampToValueAtTime(880, audioContext.currentTime + 0.3);
482
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
483
+ oscillator.start();
484
+ oscillator.stop(audioContext.currentTime + 0.3);
485
+ break;
486
+
487
+ case 'weaponSwitch':
488
+ oscillator.type = 'square';
489
+ oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
490
+ oscillator.frequency.exponentialRampToValueAtTime(880, audioContext.currentTime + 0.1);
491
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
492
+ oscillator.start();
493
+ oscillator.stop(audioContext.currentTime + 0.1);
494
+ break;
495
+ }
496
+ }
497
+
498
+ // Handle window resize
499
+ window.addEventListener('resize', () => {
500
+ canvas.width = window.innerWidth;
501
+ canvas.height = window.innerHeight;
502
+ });
503
+
504
+ // Music control functions
505
+ function playMusic() {
506
+ bgMusic.play().catch(e => {
507
+ console.error("Audio playback failed:", e);
508
+ // Show a message to the user that they need to interact first
509
+ document.getElementById('loading').textContent = "Click anywhere to start music";
510
+ document.addEventListener('click', () => {
511
+ bgMusic.play();
512
+ document.getElementById('loading').style.display = 'none';
513
+ assetsLoaded = true;
514
+ }, { once: true });
515
+ });
516
+ }
517
+
518
+ function stopMusic() {
519
+ bgMusic.pause();
520
+ }
521
+
522
+ // Setup music controls
523
+ document.getElementById('playMusic').addEventListener('click', playMusic);
524
+ document.getElementById('stopMusic').addEventListener('click', stopMusic);
525
+
526
+ // Game loop
527
+ function gameLoop(timestamp) {
528
+ if (!gameRunning || !assetsLoaded) {
529
+ requestAnimationFrame(gameLoop);
530
+ return;
531
+ }
532
+
533
+ // Calculate delta time and FPS
534
+ const deltaTime = timestamp - lastTime;
535
+ lastTime = timestamp;
536
+
537
+ if (deltaTime > 0) {
538
+ fps = 1000 / deltaTime;
539
+ frameCount++;
540
+
541
+ // Update FPS display every second
542
+ if (timestamp - lastFpsUpdate > 1000) {
543
+ document.getElementById('fps').textContent = Math.round(fps);
544
+ lastFpsUpdate = timestamp;
545
+ frameCount = 0;
546
+ }
547
+ }
548
+
549
+ // Clear canvas
550
+ ctx.fillStyle = '#000033';
551
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
552
+
553
+ // Draw scrolling background
554
+ ctx.strokeStyle = '#0066FF';
555
+ ctx.lineWidth = 2;
556
+ bgOffset += SCROLL_SPEED;
557
+
558
+ if (bgOffset >= BG_LINE_SPACING) {
559
+ bgOffset = 0;
560
+ }
561
+
562
+ for (let y = -BG_LINE_SPACING + bgOffset; y < canvas.height; y += BG_LINE_SPACING) {
563
+ ctx.beginPath();
564
+ ctx.moveTo(0, y);
565
+ ctx.lineTo(canvas.width, y);
566
+ ctx.stroke();
567
+ }
568
+
569
+ // Draw starfield background
570
+ for (let i = 0; i < 100; i++) {
571
+ const x = (i * 12345) % canvas.width;
572
+ const y = (i * 9876 + timestamp / 50) % canvas.height;
573
+ const size = (i % 3) + 1;
574
+ const opacity = 0.5 + (i % 10) / 20;
575
+
576
+ ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
577
+ ctx.fillRect(x, y, size, size);
578
+ }
579
+
580
+ // Update and draw player
581
+ player.update();
582
+ player.draw();
583
+
584
+ // Update and draw enemies
585
+ for (let i = enemies.length - 1; i >= 0; i--) {
586
+ if (!enemies[i].update()) {
587
+ enemies.splice(i, 1);
588
+ } else {
589
+ enemies[i].draw();
590
+ }
591
+ }
592
+
593
+ // Spawn new enemies occasionally
594
+ if (Math.random() < 0.02) {
595
+ spawnEnemy();
596
+ }
597
+
598
+ // Gradually decrease power level when not shooting
599
+ if (powerLevel > 0 && !keys[' ']) {
600
+ powerLevel -= 0.2;
601
+ document.getElementById('powerFill').style.width = powerLevel + '%';
602
+
603
+ // Check if weapon should downgrade
604
+ if (powerLevel <= 0 && weaponType === 'power') {
605
+ weaponType = 'normal';
606
+ document.getElementById('weapon').textContent = 'NORMAL';
607
+ }
608
+ }
609
+
610
+ requestAnimationFrame(gameLoop);
611
+ }
612
+
613
+ // Initialize the game
614
+ function initGame() {
615
+ // Hide loading screen and start game
616
+ document.getElementById('loading').style.display = 'none';
617
+ assetsLoaded = true;
618
+
619
+ // Start music
620
+ playMusic();
621
+
622
+ // Spawn initial enemies
623
+ for (let i = 0; i < 5; i++) {
624
+ setTimeout(spawnEnemy, i * 1000);
625
+ }
626
+
627
+ // Start game loop
628
+ requestAnimationFrame(gameLoop);
629
+ }
630
+
631
+ // Start the initialization process
632
+ document.addEventListener('DOMContentLoaded', () => {
633
+ // Modern browsers require user interaction before playing audio
634
+ document.addEventListener('click', () => {
635
+ initGame();
636
+ }, { once: true });
637
+
638
+ document.getElementById('loading').textContent = "Click anywhere to start game";
639
+ });
640
+ </script>
641
+ </body>
642
+ </html>