beansfotos commited on
Commit
ac5a575
·
verified ·
1 Parent(s): 4f0301a

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +913 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Galactic Defender V1
3
- emoji: 🐠
4
  colorFrom: gray
5
- colorTo: yellow
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: galactic-defender-v1
3
+ emoji: 🐳
4
  colorFrom: gray
5
+ colorTo: red
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,913 @@
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>Galactic Defender</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @keyframes enemyShoot {
11
+ 0% { transform: translateY(0); }
12
+ 100% { transform: translateY(100vh); }
13
+ }
14
+
15
+ @keyframes powerupFloat {
16
+ 0%, 100% { transform: translateY(0); }
17
+ 50% { transform: translateY(-10px); }
18
+ }
19
+
20
+ .enemy-bullet {
21
+ animation: enemyShoot linear;
22
+ }
23
+
24
+ .powerup {
25
+ animation: powerupFloat 2s ease-in-out infinite;
26
+ }
27
+
28
+ #gameCanvas {
29
+ background: linear-gradient(to bottom, #0f172a, #1e293b);
30
+ image-rendering: pixelated;
31
+ }
32
+
33
+ .explosion {
34
+ position: absolute;
35
+ width: 40px;
36
+ height: 40px;
37
+ background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="orange" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="2" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22"/><line x1="4" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="20" y2="12"/><line x1="4.93" y1="4.93" x2="6.34" y2="6.34"/><line x1="17.66" y1="17.66" x2="19.07" y2="19.07"/><line x1="4.93" y1="19.07" x2="6.34" y2="17.66"/><line x1="17.66" y1="6.34" x2="19.07" y2="4.93"/></svg>');
38
+ background-size: contain;
39
+ animation: explode 0.5s ease-out forwards;
40
+ }
41
+
42
+ @keyframes explode {
43
+ 0% { transform: scale(0.5); opacity: 1; }
44
+ 100% { transform: scale(2); opacity: 0; }
45
+ }
46
+ </style>
47
+ </head>
48
+ <body class="bg-gray-900 text-white font-mono overflow-hidden">
49
+ <div class="container mx-auto px-4 py-8 flex flex-col items-center min-h-screen">
50
+ <h1 class="text-4xl font-bold mb-4 text-center bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-600">
51
+ GALACTIC DEFENDER
52
+ </h1>
53
+
54
+ <div id="gameContainer" class="relative w-full max-w-2xl h-96 md:h-[500px] mb-4 rounded-lg overflow-hidden border-2 border-blue-500 shadow-lg shadow-blue-500/20">
55
+ <canvas id="gameCanvas" class="w-full h-full"></canvas>
56
+
57
+ <div id="startScreen" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-80 p-4">
58
+ <h2 class="text-3xl font-bold mb-6 text-blue-400">GALACTIC DEFENDER</h2>
59
+ <p class="text-lg mb-8 text-center max-w-md">Defend Earth from alien invaders! Collect powerups and survive as long as you can.</p>
60
+ <button id="startButton" class="px-8 py-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-xl font-bold transition-all transform hover:scale-105">
61
+ START MISSION
62
+ </button>
63
+ <div class="mt-8 text-sm text-gray-400">
64
+ <p class="mb-2"><i class="fas fa-arrow-left mr-2"></i> <i class="fas fa-arrow-right mr-2"></i> Move</p>
65
+ <p><i class="fas fa-space-shuttle mr-2"></i> <i class="fas fa-arrow-up mr-2"></i> Shoot</p>
66
+ </div>
67
+ </div>
68
+
69
+ <div id="gameOverScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80 p-4">
70
+ <h2 class="text-3xl font-bold mb-2 text-red-500">MISSION FAILED</h2>
71
+ <p class="text-xl mb-6">Your score: <span id="finalScore">0</span></p>
72
+ <p class="text-lg mb-4">Level reached: <span id="finalLevel">1</span></p>
73
+ <button id="restartButton" class="px-8 py-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-xl font-bold transition-all transform hover:scale-105">
74
+ TRY AGAIN
75
+ </button>
76
+ </div>
77
+
78
+ <div id="levelCompleteScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80 p-4">
79
+ <h2 class="text-3xl font-bold mb-6 text-green-400">LEVEL COMPLETE!</h2>
80
+ <p class="text-xl mb-8">Preparing for next wave...</p>
81
+ <div class="w-full max-w-xs h-2 bg-gray-700 rounded-full overflow-hidden">
82
+ <div id="levelTransitionProgress" class="h-full bg-blue-500 rounded-full transition-all duration-1000"></div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ <div class="w-full max-w-2xl flex justify-between items-center mb-4">
88
+ <div class="flex items-center">
89
+ <div class="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center mr-2">
90
+ <i class="fas fa-heart text-white"></i>
91
+ </div>
92
+ <span id="lives" class="text-xl">3</span>
93
+ </div>
94
+
95
+ <div class="text-center">
96
+ <div class="text-xl">Score: <span id="score">0</span></div>
97
+ <div class="text-sm text-gray-400">Level: <span id="level">1</span></div>
98
+ </div>
99
+
100
+ <div class="flex items-center">
101
+ <div class="w-8 h-8 bg-yellow-500 rounded-full flex items-center justify-center mr-2">
102
+ <i class="fas fa-bolt text-white"></i>
103
+ </div>
104
+ <span id="powerupTimer" class="text-xl">0</span>
105
+ </div>
106
+ </div>
107
+
108
+ <div class="w-full max-w-2xl bg-gray-800 rounded-lg p-4 mb-4">
109
+ <h3 class="text-lg font-bold mb-2 text-blue-400">POWERUPS</h3>
110
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-2">
111
+ <div class="flex items-center">
112
+ <div class="w-6 h-6 bg-red-500 rounded-full mr-2"></div>
113
+ <span class="text-sm">Rapid Fire</span>
114
+ </div>
115
+ <div class="flex items-center">
116
+ <div class="w-6 h-6 bg-green-500 rounded-full mr-2"></div>
117
+ <span class="text-sm">Shield</span>
118
+ </div>
119
+ <div class="flex items-center">
120
+ <div class="w-6 h-6 bg-yellow-500 rounded-full mr-2"></div>
121
+ <span class="text-sm">Multi-Shot</span>
122
+ </div>
123
+ <div class="flex items-center">
124
+ <div class="w-6 h-6 bg-purple-500 rounded-full mr-2"></div>
125
+ <span class="text-sm">Nuke</span>
126
+ </div>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="text-sm text-gray-500 text-center">
131
+ <p>Use arrow keys to move and spacebar to shoot</p>
132
+ <p>Collect powerups for special abilities</p>
133
+ </div>
134
+ </div>
135
+
136
+ <script>
137
+ document.addEventListener('DOMContentLoaded', () => {
138
+ // Game elements
139
+ const canvas = document.getElementById('gameCanvas');
140
+ const ctx = canvas.getContext('2d');
141
+ const startScreen = document.getElementById('startScreen');
142
+ const gameOverScreen = document.getElementById('gameOverScreen');
143
+ const levelCompleteScreen = document.getElementById('levelCompleteScreen');
144
+ const startButton = document.getElementById('startButton');
145
+ const restartButton = document.getElementById('restartButton');
146
+ const scoreDisplay = document.getElementById('score');
147
+ const livesDisplay = document.getElementById('lives');
148
+ const levelDisplay = document.getElementById('level');
149
+ const finalScoreDisplay = document.getElementById('finalScore');
150
+ const finalLevelDisplay = document.getElementById('finalLevel');
151
+ const powerupTimerDisplay = document.getElementById('powerupTimer');
152
+ const levelTransitionProgress = document.getElementById('levelTransitionProgress');
153
+
154
+ // Set canvas size
155
+ function resizeCanvas() {
156
+ const container = document.getElementById('gameContainer');
157
+ canvas.width = container.clientWidth;
158
+ canvas.height = container.clientHeight;
159
+ }
160
+
161
+ resizeCanvas();
162
+ window.addEventListener('resize', resizeCanvas);
163
+
164
+ // Game state
165
+ let gameRunning = false;
166
+ let score = 0;
167
+ let lives = 3;
168
+ let level = 1;
169
+ let enemies = [];
170
+ let enemyBullets = [];
171
+ let playerBullets = [];
172
+ let explosions = [];
173
+ let powerups = [];
174
+ let activePowerup = null;
175
+ let powerupTimeLeft = 0;
176
+
177
+ // Player
178
+ const player = {
179
+ x: canvas.width / 2 - 25,
180
+ y: canvas.height - 60,
181
+ width: 50,
182
+ height: 40,
183
+ speed: 8,
184
+ color: '#3b82f6',
185
+ isShielded: false,
186
+ lastShot: 0,
187
+ shootDelay: 500, // ms between shots
188
+ moveLeft: false,
189
+ moveRight: false
190
+ };
191
+
192
+ // Powerup types
193
+ const POWERUP_TYPES = {
194
+ RAPID_FIRE: {
195
+ color: '#ef4444',
196
+ duration: 10000, // 10 seconds
197
+ effect: () => {
198
+ player.shootDelay = 200;
199
+ },
200
+ reset: () => {
201
+ player.shootDelay = 500;
202
+ }
203
+ },
204
+ SHIELD: {
205
+ color: '#10b981',
206
+ duration: 8000, // 8 seconds
207
+ effect: () => {
208
+ player.isShielded = true;
209
+ },
210
+ reset: () => {
211
+ player.isShielded = false;
212
+ }
213
+ },
214
+ MULTI_SHOT: {
215
+ color: '#eab308',
216
+ duration: 7000, // 7 seconds
217
+ effect: () => {}, // Handled in shooting logic
218
+ reset: () => {}
219
+ },
220
+ NUKE: {
221
+ color: '#8b5cf6',
222
+ duration: 0, // Instant effect
223
+ effect: () => {
224
+ // Destroy all enemies
225
+ enemies.forEach(enemy => {
226
+ createExplosion(enemy.x + enemy.width/2, enemy.y + enemy.height/2);
227
+ score += enemy.points;
228
+ });
229
+ enemies = [];
230
+ scoreDisplay.textContent = score;
231
+ },
232
+ reset: () => {}
233
+ }
234
+ };
235
+
236
+ // Initialize level
237
+ function initLevel() {
238
+ enemies = [];
239
+ enemyBullets = [];
240
+
241
+ const enemyRows = Math.min(3 + Math.floor(level / 2), 6);
242
+ const enemyCols = Math.min(5 + Math.floor(level / 3), 10);
243
+ const enemyWidth = 40;
244
+ const enemyHeight = 30;
245
+ const padding = 10;
246
+ const startX = (canvas.width - (enemyCols * (enemyWidth + padding))) / 2;
247
+
248
+ for (let row = 0; row < enemyRows; row++) {
249
+ for (let col = 0; col < enemyCols; col++) {
250
+ const enemyType = Math.floor(Math.random() * 3);
251
+ let color, points;
252
+
253
+ switch (enemyType) {
254
+ case 0: // Basic enemy
255
+ color = '#f43f5e';
256
+ points = 10 * level;
257
+ break;
258
+ case 1: // Fast enemy
259
+ color = '#f97316';
260
+ points = 20 * level;
261
+ break;
262
+ case 2: // Strong enemy
263
+ color = '#6366f1';
264
+ points = 30 * level;
265
+ break;
266
+ }
267
+
268
+ enemies.push({
269
+ x: startX + col * (enemyWidth + padding),
270
+ y: 30 + row * (enemyHeight + padding),
271
+ width: enemyWidth,
272
+ height: enemyHeight,
273
+ color: color,
274
+ speed: 1 + (level * 0.2) + (enemyType === 1 ? 1 : 0),
275
+ points: points,
276
+ health: enemyType === 2 ? 2 : 1,
277
+ shootDelay: 2000 + Math.random() * 3000 - (level * 100),
278
+ lastShot: 0,
279
+ direction: 1
280
+ });
281
+ }
282
+ }
283
+
284
+ levelDisplay.textContent = level;
285
+ }
286
+
287
+ // Create explosion effect
288
+ function createExplosion(x, y) {
289
+ explosions.push({
290
+ x: x - 20,
291
+ y: y - 20,
292
+ time: 0,
293
+ duration: 500
294
+ });
295
+ }
296
+
297
+ // Spawn a random powerup
298
+ function spawnPowerup(x, y) {
299
+ // 30% chance to spawn a powerup
300
+ if (Math.random() > 0.3) return;
301
+
302
+ const powerupKeys = Object.keys(POWERUP_TYPES);
303
+ const randomPowerup = powerupKeys[Math.floor(Math.random() * powerupKeys.length)];
304
+
305
+ powerups.push({
306
+ x: x,
307
+ y: y,
308
+ width: 20,
309
+ height: 20,
310
+ type: POWERUP_TYPES[randomPowerup],
311
+ color: POWERUP_TYPES[randomPowerup].color
312
+ });
313
+ }
314
+
315
+ // Activate a powerup
316
+ function activatePowerup(powerup) {
317
+ // If there's already an active powerup, reset it first
318
+ if (activePowerup) {
319
+ activePowerup.reset();
320
+ }
321
+
322
+ activePowerup = powerup.type;
323
+ powerupTimeLeft = powerup.type.duration;
324
+ powerup.type.effect();
325
+
326
+ // Update UI
327
+ powerupTimerDisplay.textContent = Math.ceil(powerupTimeLeft / 1000);
328
+ powerupTimerDisplay.parentElement.classList.remove('text-gray-400');
329
+ powerupTimerDisplay.parentElement.classList.add('text-yellow-400');
330
+ }
331
+
332
+ // Reset active powerup
333
+ function resetPowerup() {
334
+ if (activePowerup) {
335
+ activePowerup.reset();
336
+ activePowerup = null;
337
+ powerupTimeLeft = 0;
338
+
339
+ // Update UI
340
+ powerupTimerDisplay.textContent = '0';
341
+ powerupTimerDisplay.parentElement.classList.remove('text-yellow-400');
342
+ powerupTimerDisplay.parentElement.classList.add('text-gray-400');
343
+ }
344
+ }
345
+
346
+ // Player shooting
347
+ function playerShoot() {
348
+ const now = Date.now();
349
+ if (now - player.lastShot < player.shootDelay) return;
350
+
351
+ player.lastShot = now;
352
+
353
+ if (activePowerup === POWERUP_TYPES.MULTI_SHOT) {
354
+ // Triple shot
355
+ playerBullets.push({
356
+ x: player.x + player.width/2 - 2,
357
+ y: player.y,
358
+ width: 4,
359
+ height: 10,
360
+ color: '#ffffff',
361
+ speed: 10,
362
+ angle: 0 // Straight up
363
+ });
364
+
365
+ playerBullets.push({
366
+ x: player.x + player.width/2 - 2,
367
+ y: player.y,
368
+ width: 4,
369
+ height: 10,
370
+ color: '#ffffff',
371
+ speed: 10,
372
+ angle: -0.3 // Left angle
373
+ });
374
+
375
+ playerBullets.push({
376
+ x: player.x + player.width/2 - 2,
377
+ y: player.y,
378
+ width: 4,
379
+ height: 10,
380
+ color: '#ffffff',
381
+ speed: 10,
382
+ angle: 0.3 // Right angle
383
+ });
384
+ } else {
385
+ // Single shot
386
+ playerBullets.push({
387
+ x: player.x + player.width/2 - 2,
388
+ y: player.y,
389
+ width: 4,
390
+ height: 10,
391
+ color: '#ffffff',
392
+ speed: 10,
393
+ angle: 0
394
+ });
395
+ }
396
+ }
397
+
398
+ // Enemy shooting
399
+ function enemyShoot(enemy) {
400
+ const now = Date.now();
401
+ if (now - enemy.lastShot < enemy.shootDelay) return;
402
+
403
+ enemy.lastShot = now;
404
+
405
+ enemyBullets.push({
406
+ x: enemy.x + enemy.width/2 - 2,
407
+ y: enemy.y + enemy.height,
408
+ width: 4,
409
+ height: 10,
410
+ color: '#f43f5e',
411
+ speed: 5 + (level * 0.5),
412
+ angle: 0
413
+ });
414
+ }
415
+
416
+ // Check collision between two objects
417
+ function checkCollision(obj1, obj2) {
418
+ return obj1.x < obj2.x + obj2.width &&
419
+ obj1.x + obj1.width > obj2.x &&
420
+ obj1.y < obj2.y + obj2.height &&
421
+ obj1.y + obj1.height > obj2.y;
422
+ }
423
+
424
+ // Game loop
425
+ function gameLoop() {
426
+ if (!gameRunning) return;
427
+
428
+ // Clear canvas
429
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
430
+
431
+ // Draw starfield background
432
+ drawStarfield();
433
+
434
+ // Update player position
435
+ if (player.moveLeft && player.x > 0) {
436
+ player.x -= player.speed;
437
+ }
438
+ if (player.moveRight && player.x < canvas.width - player.width) {
439
+ player.x += player.speed;
440
+ }
441
+
442
+ // Draw player
443
+ drawPlayer();
444
+
445
+ // Update and draw bullets
446
+ updateBullets();
447
+
448
+ // Update and draw enemies
449
+ updateEnemies();
450
+
451
+ // Update and draw powerups
452
+ updatePowerups();
453
+
454
+ // Update and draw explosions
455
+ updateExplosions();
456
+
457
+ // Update active powerup timer
458
+ updatePowerupTimer();
459
+
460
+ // Check for level completion
461
+ if (enemies.length === 0) {
462
+ levelComplete();
463
+ return;
464
+ }
465
+
466
+ // Continue game loop
467
+ requestAnimationFrame(gameLoop);
468
+ }
469
+
470
+ // Draw starfield background
471
+ function drawStarfield() {
472
+ ctx.fillStyle = '#ffffff';
473
+
474
+ // Draw some static stars
475
+ for (let i = 0; i < 50; i++) {
476
+ const x = (i * 12345) % canvas.width;
477
+ const y = (i * 54321) % canvas.height;
478
+ const size = Math.random() * 1.5;
479
+
480
+ ctx.beginPath();
481
+ ctx.arc(x, y, size, 0, Math.PI * 2);
482
+ ctx.fill();
483
+ }
484
+
485
+ // Draw some twinkling stars
486
+ const time = Date.now();
487
+ for (let i = 0; i < 20; i++) {
488
+ const x = (i * 67890) % canvas.width;
489
+ const y = (i * 9876) % canvas.height;
490
+ const size = 1 + Math.sin(time * 0.001 + i) * 0.5;
491
+
492
+ ctx.beginPath();
493
+ ctx.arc(x, y, size, 0, Math.PI * 2);
494
+ ctx.fill();
495
+ }
496
+ }
497
+
498
+ // Draw player ship
499
+ function drawPlayer() {
500
+ // Draw shield if active
501
+ if (player.isShielded) {
502
+ ctx.beginPath();
503
+ ctx.arc(player.x + player.width/2, player.y + player.height/2, player.width/2 + 10, 0, Math.PI * 2);
504
+ ctx.strokeStyle = '#10b981';
505
+ ctx.lineWidth = 2;
506
+ ctx.stroke();
507
+ }
508
+
509
+ // Draw ship body
510
+ ctx.fillStyle = player.color;
511
+ ctx.beginPath();
512
+ ctx.moveTo(player.x + player.width/2, player.y);
513
+ ctx.lineTo(player.x + player.width, player.y + player.height);
514
+ ctx.lineTo(player.x, player.y + player.height);
515
+ ctx.closePath();
516
+ ctx.fill();
517
+
518
+ // Draw ship details
519
+ ctx.fillStyle = '#93c5fd';
520
+ ctx.beginPath();
521
+ ctx.moveTo(player.x + player.width/2, player.y + 10);
522
+ ctx.lineTo(player.x + player.width - 10, player.y + player.height - 5);
523
+ ctx.lineTo(player.x + 10, player.y + player.height - 5);
524
+ ctx.closePath();
525
+ ctx.fill();
526
+
527
+ // Draw engine glow
528
+ const time = Date.now();
529
+ const glowSize = 5 + Math.sin(time * 0.01) * 2;
530
+
531
+ ctx.fillStyle = '#f59e0b';
532
+ ctx.beginPath();
533
+ ctx.moveTo(player.x + player.width/2 - 5, player.y + player.height);
534
+ ctx.lineTo(player.x + player.width/2 + 5, player.y + player.height);
535
+ ctx.lineTo(player.x + player.width/2, player.y + player.height + glowSize);
536
+ ctx.closePath();
537
+ ctx.fill();
538
+ }
539
+
540
+ // Update and draw bullets
541
+ function updateBullets() {
542
+ // Player bullets
543
+ for (let i = playerBullets.length - 1; i >= 0; i--) {
544
+ const bullet = playerBullets[i];
545
+
546
+ // Update position based on angle
547
+ bullet.x += Math.sin(bullet.angle) * 5;
548
+ bullet.y -= bullet.speed;
549
+
550
+ // Draw bullet
551
+ ctx.fillStyle = bullet.color;
552
+ ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
553
+
554
+ // Remove if off screen
555
+ if (bullet.y + bullet.height < 0) {
556
+ playerBullets.splice(i, 1);
557
+ continue;
558
+ }
559
+
560
+ // Check collision with enemies
561
+ for (let j = enemies.length - 1; j >= 0; j--) {
562
+ const enemy = enemies[j];
563
+
564
+ if (checkCollision(bullet, enemy)) {
565
+ // Hit enemy
566
+ enemy.health--;
567
+
568
+ if (enemy.health <= 0) {
569
+ // Enemy destroyed
570
+ createExplosion(enemy.x + enemy.width/2, enemy.y + enemy.height/2);
571
+ score += enemy.points;
572
+ scoreDisplay.textContent = score;
573
+
574
+ // Chance to spawn powerup
575
+ spawnPowerup(enemy.x + enemy.width/2, enemy.y + enemy.height/2);
576
+
577
+ enemies.splice(j, 1);
578
+ }
579
+
580
+ playerBullets.splice(i, 1);
581
+ break;
582
+ }
583
+ }
584
+ }
585
+
586
+ // Enemy bullets
587
+ for (let i = enemyBullets.length - 1; i >= 0; i--) {
588
+ const bullet = enemyBullets[i];
589
+
590
+ bullet.y += bullet.speed;
591
+
592
+ // Draw bullet
593
+ ctx.fillStyle = bullet.color;
594
+ ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
595
+
596
+ // Remove if off screen
597
+ if (bullet.y > canvas.height) {
598
+ enemyBullets.splice(i, 1);
599
+ continue;
600
+ }
601
+
602
+ // Check collision with player
603
+ if (checkCollision(bullet, player)) {
604
+ if (player.isShielded) {
605
+ // Shield blocks the bullet
606
+ createExplosion(bullet.x + bullet.width/2, bullet.y + bullet.height/2);
607
+ } else {
608
+ // Player hit
609
+ lives--;
610
+ livesDisplay.textContent = lives;
611
+ createExplosion(player.x + player.width/2, player.y + player.height/2);
612
+
613
+ if (lives <= 0) {
614
+ gameOver();
615
+ return;
616
+ }
617
+ }
618
+
619
+ enemyBullets.splice(i, 1);
620
+ }
621
+ }
622
+ }
623
+
624
+ // Update and draw enemies
625
+ function updateEnemies() {
626
+ let moveDown = false;
627
+ let edgeReached = false;
628
+
629
+ // Check if any enemy has reached the edge
630
+ for (const enemy of enemies) {
631
+ if ((enemy.x <= 0 && enemy.direction === -1) ||
632
+ (enemy.x + enemy.width >= canvas.width && enemy.direction === 1)) {
633
+ edgeReached = true;
634
+ break;
635
+ }
636
+ }
637
+
638
+ // Update enemy positions
639
+ for (const enemy of enemies) {
640
+ // Change direction if edge reached
641
+ if (edgeReached) {
642
+ enemy.direction *= -1;
643
+ moveDown = true;
644
+ }
645
+
646
+ // Move horizontally
647
+ enemy.x += enemy.speed * enemy.direction;
648
+
649
+ // Move down if needed
650
+ if (moveDown) {
651
+ enemy.y += 20;
652
+ }
653
+
654
+ // Random shooting
655
+ if (Math.random() < 0.02) {
656
+ enemyShoot(enemy);
657
+ }
658
+
659
+ // Draw enemy
660
+ ctx.fillStyle = enemy.color;
661
+
662
+ // Different enemy shapes based on type
663
+ if (enemy.color === '#f43f5e') { // Basic enemy
664
+ ctx.beginPath();
665
+ ctx.moveTo(enemy.x + enemy.width/2, enemy.y);
666
+ ctx.lineTo(enemy.x + enemy.width, enemy.y + enemy.height);
667
+ ctx.lineTo(enemy.x, enemy.y + enemy.height);
668
+ ctx.closePath();
669
+ ctx.fill();
670
+ } else if (enemy.color === '#f97316') { // Fast enemy
671
+ ctx.beginPath();
672
+ ctx.ellipse(enemy.x + enemy.width/2, enemy.y + enemy.height/2,
673
+ enemy.width/2, enemy.height/2, 0, 0, Math.PI * 2);
674
+ ctx.fill();
675
+ } else { // Strong enemy
676
+ ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
677
+
678
+ // Draw armor detail
679
+ ctx.fillStyle = '#a5b4fc';
680
+ ctx.fillRect(enemy.x + 5, enemy.y + 5, enemy.width - 10, enemy.height - 10);
681
+ }
682
+
683
+ // Check if enemy reached bottom
684
+ if (enemy.y + enemy.height >= canvas.height - 40) {
685
+ gameOver();
686
+ return;
687
+ }
688
+
689
+ // Check collision with player
690
+ if (checkCollision(enemy, player)) {
691
+ gameOver();
692
+ return;
693
+ }
694
+ }
695
+ }
696
+
697
+ // Update and draw powerups
698
+ function updatePowerups() {
699
+ for (let i = powerups.length - 1; i >= 0; i--) {
700
+ const powerup = powerups[i];
701
+
702
+ // Move down
703
+ powerup.y += 2;
704
+
705
+ // Draw powerup
706
+ ctx.fillStyle = powerup.color;
707
+ ctx.beginPath();
708
+ ctx.arc(powerup.x + powerup.width/2, powerup.y + powerup.height/2,
709
+ powerup.width/2, 0, Math.PI * 2);
710
+ ctx.fill();
711
+
712
+ // Add some glow
713
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
714
+ ctx.beginPath();
715
+ ctx.arc(powerup.x + powerup.width/2, powerup.y + powerup.height/2,
716
+ powerup.width/2 + 3, 0, Math.PI * 2);
717
+ ctx.fill();
718
+
719
+ // Remove if off screen
720
+ if (powerup.y > canvas.height) {
721
+ powerups.splice(i, 1);
722
+ continue;
723
+ }
724
+
725
+ // Check collision with player
726
+ if (checkCollision(powerup, player)) {
727
+ activatePowerup(powerup);
728
+ powerups.splice(i, 1);
729
+ }
730
+ }
731
+ }
732
+
733
+ // Update and draw explosions
734
+ function updateExplosions() {
735
+ for (let i = explosions.length - 1; i >= 0; i--) {
736
+ const explosion = explosions[i];
737
+ explosion.time += 16; // Approximate 60fps frame time
738
+
739
+ // Draw explosion
740
+ const progress = explosion.time / explosion.duration;
741
+ const size = 20 + progress * 40;
742
+ const alpha = 1 - progress;
743
+
744
+ ctx.save();
745
+ ctx.translate(explosion.x + 20, explosion.y + 20);
746
+ ctx.scale(progress * 2, progress * 2);
747
+
748
+ // Draw explosion particles
749
+ for (let j = 0; j < 8; j++) {
750
+ const angle = (j / 8) * Math.PI * 2;
751
+ const length = 5 + Math.random() * 5;
752
+
753
+ ctx.beginPath();
754
+ ctx.moveTo(0, 0);
755
+ ctx.lineTo(Math.cos(angle) * length, Math.sin(angle) * length);
756
+ ctx.strokeStyle = `rgba(255, ${100 + Math.random() * 155}, 0, ${alpha})`;
757
+ ctx.lineWidth = 2;
758
+ ctx.stroke();
759
+ }
760
+
761
+ ctx.restore();
762
+
763
+ // Remove if animation complete
764
+ if (explosion.time >= explosion.duration) {
765
+ explosions.splice(i, 1);
766
+ }
767
+ }
768
+ }
769
+
770
+ // Update active powerup timer
771
+ function updatePowerupTimer() {
772
+ if (activePowerup && powerupTimeLeft > 0) {
773
+ powerupTimeLeft -= 16; // Approximate 60fps frame time
774
+ powerupTimerDisplay.textContent = Math.ceil(powerupTimeLeft / 1000);
775
+
776
+ if (powerupTimeLeft <= 0) {
777
+ resetPowerup();
778
+ }
779
+ }
780
+ }
781
+
782
+ // Game over
783
+ function gameOver() {
784
+ gameRunning = false;
785
+ finalScoreDisplay.textContent = score;
786
+ finalLevelDisplay.textContent = level;
787
+ gameOverScreen.classList.remove('hidden');
788
+ }
789
+
790
+ // Level complete
791
+ function levelComplete() {
792
+ gameRunning = false;
793
+ levelCompleteScreen.classList.remove('hidden');
794
+
795
+ // Animate progress bar
796
+ levelTransitionProgress.style.width = '0%';
797
+ setTimeout(() => {
798
+ levelTransitionProgress.style.width = '100%';
799
+ }, 10);
800
+
801
+ // Advance to next level after delay
802
+ setTimeout(() => {
803
+ level++;
804
+ initLevel();
805
+ levelCompleteScreen.classList.add('hidden');
806
+ startGame();
807
+ }, 2000);
808
+ }
809
+
810
+ // Start game
811
+ function startGame() {
812
+ // Reset game state
813
+ score = 0;
814
+ lives = 3;
815
+ level = 1;
816
+ playerBullets = [];
817
+ enemyBullets = [];
818
+ explosions = [];
819
+ powerups = [];
820
+ resetPowerup();
821
+
822
+ // Update UI
823
+ scoreDisplay.textContent = score;
824
+ livesDisplay.textContent = lives;
825
+ levelDisplay.textContent = level;
826
+
827
+ // Initialize first level
828
+ initLevel();
829
+
830
+ // Hide screens
831
+ startScreen.classList.add('hidden');
832
+ gameOverScreen.classList.add('hidden');
833
+
834
+ // Start game loop
835
+ gameRunning = true;
836
+ gameLoop();
837
+ }
838
+
839
+ // Restart game
840
+ function restartGame() {
841
+ gameOverScreen.classList.add('hidden');
842
+ startGame();
843
+ }
844
+
845
+ // Event listeners
846
+ startButton.addEventListener('click', startGame);
847
+ restartButton.addEventListener('click', restartGame);
848
+
849
+ // Keyboard controls
850
+ document.addEventListener('keydown', (e) => {
851
+ if (!gameRunning) return;
852
+
853
+ switch (e.key) {
854
+ case 'ArrowLeft':
855
+ player.moveLeft = true;
856
+ break;
857
+ case 'ArrowRight':
858
+ player.moveRight = true;
859
+ break;
860
+ case ' ':
861
+ case 'ArrowUp':
862
+ playerShoot();
863
+ break;
864
+ }
865
+ });
866
+
867
+ document.addEventListener('keyup', (e) => {
868
+ switch (e.key) {
869
+ case 'ArrowLeft':
870
+ player.moveLeft = false;
871
+ break;
872
+ case 'ArrowRight':
873
+ player.moveRight = false;
874
+ break;
875
+ }
876
+ });
877
+
878
+ // Touch controls for mobile
879
+ let touchStartX = 0;
880
+
881
+ canvas.addEventListener('touchstart', (e) => {
882
+ if (!gameRunning) return;
883
+
884
+ touchStartX = e.touches[0].clientX;
885
+ playerShoot();
886
+ e.preventDefault();
887
+ });
888
+
889
+ canvas.addEventListener('touchmove', (e) => {
890
+ if (!gameRunning) return;
891
+
892
+ const touchX = e.touches[0].clientX;
893
+ const diff = touchX - touchStartX;
894
+
895
+ if (diff > 10) {
896
+ player.moveRight = true;
897
+ player.moveLeft = false;
898
+ } else if (diff < -10) {
899
+ player.moveLeft = true;
900
+ player.moveRight = false;
901
+ }
902
+
903
+ e.preventDefault();
904
+ });
905
+
906
+ canvas.addEventListener('touchend', () => {
907
+ player.moveLeft = false;
908
+ player.moveRight = false;
909
+ });
910
+ });
911
+ </script>
912
+ <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=beansfotos/galactic-defender-v1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
913
+ </html>