offerpk3 commited on
Commit
680f57f
·
verified ·
1 Parent(s): 7e78268

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +723 -19
index.html CHANGED
@@ -1,19 +1,723 @@
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>Fish.io - Territory Game</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 20px;
11
+ background: linear-gradient(180deg, #001133 0%, #003366 50%, #004080 100%);
12
+ font-family: 'Arial', sans-serif;
13
+ color: white;
14
+ overflow: hidden;
15
+ }
16
+
17
+ .game-container {
18
+ display: flex;
19
+ justify-content: center;
20
+ align-items: center;
21
+ min-height: 100vh;
22
+ flex-direction: column;
23
+ }
24
+
25
+ .ui-panel {
26
+ display: flex;
27
+ justify-content: space-between;
28
+ width: 800px;
29
+ margin-bottom: 10px;
30
+ font-size: 18px;
31
+ font-weight: bold;
32
+ }
33
+
34
+ .score-info {
35
+ background: rgba(0, 50, 100, 0.8);
36
+ padding: 10px 20px;
37
+ border-radius: 10px;
38
+ border: 2px solid #00ccff;
39
+ }
40
+
41
+ #gameCanvas {
42
+ border: 3px solid #00ccff;
43
+ border-radius: 10px;
44
+ box-shadow: 0 0 30px rgba(0, 204, 255, 0.5);
45
+ background: linear-gradient(45deg, #001a33, #002d5a);
46
+ }
47
+
48
+ .menu-overlay {
49
+ position: absolute;
50
+ top: 0;
51
+ left: 0;
52
+ width: 100%;
53
+ height: 100%;
54
+ background: rgba(0, 20, 40, 0.95);
55
+ display: flex;
56
+ flex-direction: column;
57
+ justify-content: center;
58
+ align-items: center;
59
+ z-index: 100;
60
+ }
61
+
62
+ .menu-title {
63
+ font-size: 48px;
64
+ font-weight: bold;
65
+ color: #00ccff;
66
+ text-shadow: 0 0 20px #00ccff;
67
+ margin-bottom: 20px;
68
+ }
69
+
70
+ .menu-subtitle {
71
+ font-size: 20px;
72
+ margin-bottom: 30px;
73
+ text-align: center;
74
+ line-height: 1.5;
75
+ }
76
+
77
+ .menu-button {
78
+ background: linear-gradient(45deg, #0066cc, #00ccff);
79
+ border: none;
80
+ padding: 15px 40px;
81
+ font-size: 20px;
82
+ font-weight: bold;
83
+ color: white;
84
+ border-radius: 25px;
85
+ cursor: pointer;
86
+ transition: all 0.3s ease;
87
+ margin: 10px;
88
+ }
89
+
90
+ .menu-button:hover {
91
+ transform: scale(1.1);
92
+ box-shadow: 0 0 20px #00ccff;
93
+ }
94
+
95
+ .controls {
96
+ font-size: 16px;
97
+ margin-top: 20px;
98
+ text-align: center;
99
+ opacity: 0.8;
100
+ }
101
+
102
+ .how-to-play {
103
+ background: rgba(0, 50, 100, 0.9);
104
+ border: 2px solid #00ccff;
105
+ border-radius: 15px;
106
+ padding: 20px;
107
+ margin: 20px;
108
+ max-width: 600px;
109
+ text-align: left;
110
+ line-height: 1.6;
111
+ }
112
+
113
+ .how-to-play h3 {
114
+ color: #00ccff;
115
+ text-align: center;
116
+ margin-bottom: 15px;
117
+ }
118
+
119
+ .how-to-play ul {
120
+ margin: 10px 0;
121
+ padding-left: 20px;
122
+ }
123
+
124
+ .how-to-play li {
125
+ margin: 5px 0;
126
+ }
127
+
128
+ .hidden {
129
+ display: none;
130
+ }
131
+
132
+ .game-over-stats {
133
+ font-size: 18px;
134
+ margin: 20px 0;
135
+ text-align: center;
136
+ }
137
+ </style>
138
+ </head>
139
+ <body>
140
+ <div class="game-container">
141
+ <div class="ui-panel">
142
+ <div class="score-info">
143
+ <div>Territory: <span id="territoryScore">0</span>%</div>
144
+ </div>
145
+ <div class="score-info">
146
+ <div>Time: <span id="timeScore">0</span>s</div>
147
+ </div>
148
+ <div class="score-info">
149
+ <div>Enemies: <span id="enemyCount">0</span></div>
150
+ </div>
151
+ <div class="score-info">
152
+ <div>Kills: <span id="killCount">0</span></div>
153
+ </div>
154
+ </div>
155
+
156
+ <canvas id="gameCanvas" width="800" height="600"></canvas>
157
+
158
+ <div id="startMenu" class="menu-overlay">
159
+ <div class="menu-title">🐠 FISH.IO 🐠</div>
160
+ <div class="menu-subtitle">
161
+ Control your fish to claim territory and defend yourself!
162
+ </div>
163
+
164
+ <div class="how-to-play">
165
+ <h3>🎯 HOW TO PLAY</h3>
166
+ <strong>🏊 Movement:</strong>
167
+ <ul>
168
+ <li>Use ARROW KEYS or WASD to move your fish</li>
169
+ <li>Stay in blue territory (safe zone) or venture out to expand</li>
170
+ </ul>
171
+
172
+ <strong>🏆 Territory Claiming:</strong>
173
+ <ul>
174
+ <li>Leave your territory to create a yellow trail</li>
175
+ <li>Return to your territory to claim the enclosed area</li>
176
+ <li>Larger territory = higher score</li>
177
+ </ul>
178
+
179
+ <strong>⚔️ Combat System:</strong>
180
+ <ul>
181
+ <li>Your fish auto-fires at nearby enemies</li>
182
+ <li>Eliminate enemies to reduce threats</li>
183
+ <li>Each kill doubles the enemy count - be strategic!</li>
184
+ </ul>
185
+
186
+ <strong>⚠️ Dangers:</strong>
187
+ <ul>
188
+ <li>Enemy fish can kill you on contact</li>
189
+ <li>Your trail is vulnerable when outside territory</li>
190
+ <li>More enemies spawn as you progress</li>
191
+ </ul>
192
+ </div>
193
+
194
+ <button class="menu-button" onclick="startGame()">START GAME</button>
195
+ </div>
196
+
197
+ <div id="gameOverMenu" class="menu-overlay hidden">
198
+ <div class="menu-title">GAME OVER</div>
199
+ <div class="game-over-stats" id="finalStats"></div>
200
+ <button class="menu-button" onclick="restartGame()">🔄 RESTART GAME</button>
201
+ <button class="menu-button" onclick="showStartMenu()">🏠 MAIN MENU</button>
202
+ </div>
203
+ </div>
204
+
205
+ <script>
206
+ const canvas = document.getElementById('gameCanvas');
207
+ const ctx = canvas.getContext('2d');
208
+
209
+ // Audio context for background music
210
+ let audioContext;
211
+ let backgroundMusic;
212
+ let gameRunning = false;
213
+
214
+ // Game state
215
+ let player = {
216
+ x: 100,
217
+ y: 300,
218
+ size: 15,
219
+ speed: 3,
220
+ color: '#00ccff',
221
+ trail: [],
222
+ inTerritory: true,
223
+ fireRate: 500, // milliseconds between shots
224
+ lastShot: 0,
225
+ range: 100
226
+ };
227
+
228
+ let enemies = [];
229
+ let bullets = [];
230
+ let territory = new Set();
231
+ let claimedArea = new Set();
232
+ let gameTime = 0;
233
+ let level = 1;
234
+ let lastTime = 0;
235
+ let killCount = 0;
236
+
237
+ // Initialize territory around player start
238
+ for(let x = 80; x <= 120; x += 2) {
239
+ for(let y = 280; y <= 320; y += 2) {
240
+ territory.add(`${x},${y}`);
241
+ claimedArea.add(`${x},${y}`);
242
+ }
243
+ }
244
+
245
+ // Input handling
246
+ const keys = {};
247
+ document.addEventListener('keydown', (e) => {
248
+ keys[e.key.toLowerCase()] = true;
249
+ });
250
+ document.addEventListener('keyup', (e) => {
251
+ keys[e.key.toLowerCase()] = false;
252
+ });
253
+
254
+ // Initialize audio
255
+ function initAudio() {
256
+ if (!audioContext) {
257
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
258
+ createBackgroundMusic();
259
+ }
260
+ }
261
+
262
+ function createBackgroundMusic() {
263
+ // Create a simple ambient underwater music
264
+ const oscillator1 = audioContext.createOscillator();
265
+ const oscillator2 = audioContext.createOscillator();
266
+ const gainNode = audioContext.createGain();
267
+ const filter = audioContext.createBiquadFilter();
268
+
269
+ oscillator1.type = 'sine';
270
+ oscillator2.type = 'sine';
271
+ oscillator1.frequency.setValueAtTime(220, audioContext.currentTime);
272
+ oscillator2.frequency.setValueAtTime(165, audioContext.currentTime);
273
+
274
+ filter.type = 'lowpass';
275
+ filter.frequency.setValueAtTime(800, audioContext.currentTime);
276
+
277
+ gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
278
+
279
+ oscillator1.connect(filter);
280
+ oscillator2.connect(filter);
281
+ filter.connect(gainNode);
282
+ gainNode.connect(audioContext.destination);
283
+
284
+ // Add some variation
285
+ setInterval(() => {
286
+ if (gameRunning && audioContext) {
287
+ const freq1 = 220 + Math.sin(Date.now() * 0.001) * 30;
288
+ const freq2 = 165 + Math.cos(Date.now() * 0.0007) * 20;
289
+ oscillator1.frequency.setValueAtTime(freq1, audioContext.currentTime);
290
+ oscillator2.frequency.setValueAtTime(freq2, audioContext.currentTime);
291
+ }
292
+ }, 100);
293
+
294
+ oscillator1.start();
295
+ oscillator2.start();
296
+ backgroundMusic = { oscillator1, oscillator2, gainNode };
297
+ }
298
+
299
+ function startGame() {
300
+ document.getElementById('startMenu').classList.add('hidden');
301
+ gameRunning = true;
302
+ initAudio();
303
+ resetGame();
304
+ gameLoop();
305
+ }
306
+
307
+ function resetGame() {
308
+ player = {
309
+ x: 100,
310
+ y: 300,
311
+ size: 15,
312
+ speed: 3,
313
+ color: '#00ccff',
314
+ trail: [],
315
+ inTerritory: true,
316
+ fireRate: 500,
317
+ lastShot: 0,
318
+ range: 100
319
+ };
320
+
321
+ enemies = [];
322
+ bullets = [];
323
+ territory = new Set();
324
+ claimedArea = new Set();
325
+ gameTime = 0;
326
+ level = 1;
327
+ killCount = 0;
328
+
329
+ // Initialize territory
330
+ for(let x = 80; x <= 120; x += 2) {
331
+ for(let y = 280; y <= 320; y += 2) {
332
+ territory.add(`${x},${y}`);
333
+ claimedArea.add(`${x},${y}`);
334
+ }
335
+ }
336
+
337
+ spawnEnemies();
338
+ }
339
+
340
+ function spawnEnemies() {
341
+ // Don't clear existing enemies, just add new ones
342
+ const newEnemyCount = Math.max(1, 2 + Math.floor(level * 0.5));
343
+
344
+ for(let i = 0; i < newEnemyCount; i++) {
345
+ let x, y;
346
+ do {
347
+ x = Math.random() * (canvas.width - 60) + 30;
348
+ y = Math.random() * (canvas.height - 60) + 30;
349
+ } while(Math.abs(x - player.x) < 150 || Math.abs(y - player.y) < 150);
350
+
351
+ enemies.push({
352
+ x: x,
353
+ y: y,
354
+ size: 12 + Math.random() * 8,
355
+ speed: 1.5 + Math.random() * 1.5 + level * 0.2,
356
+ color: `hsl(${Math.random() * 360}, 70%, 60%)`,
357
+ direction: Math.random() * Math.PI * 2,
358
+ changeDirection: 0,
359
+ health: 1
360
+ });
361
+ }
362
+ }
363
+
364
+ function gameOver() {
365
+ gameRunning = false;
366
+ if (backgroundMusic && audioContext) {
367
+ backgroundMusic.gainNode.gain.setValueAtTime(0, audioContext.currentTime);
368
+ }
369
+
370
+ const territoryPercent = Math.floor((claimedArea.size / (canvas.width * canvas.height / 4)) * 100);
371
+ document.getElementById('finalStats').innerHTML = `
372
+ Territory Claimed: ${territoryPercent}%<br>
373
+ Time Survived: ${gameTime}s<br>
374
+ Enemies Defeated: ${killCount}<br>
375
+ Level Reached: ${level}
376
+ `;
377
+ document.getElementById('gameOverMenu').classList.remove('hidden');
378
+ }
379
+
380
+ function restartGame() {
381
+ document.getElementById('gameOverMenu').classList.add('hidden');
382
+ gameRunning = true;
383
+ if (backgroundMusic && audioContext) {
384
+ backgroundMusic.gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
385
+ }
386
+ resetGame();
387
+ gameLoop();
388
+ }
389
+
390
+ function showStartMenu() {
391
+ document.getElementById('gameOverMenu').classList.add('hidden');
392
+ document.getElementById('startMenu').classList.remove('hidden');
393
+ if (backgroundMusic && audioContext) {
394
+ backgroundMusic.gainNode.gain.setValueAtTime(0, audioContext.currentTime);
395
+ }
396
+ }
397
+
398
+ function updatePlayer() {
399
+ // Movement
400
+ if (keys['arrowup'] || keys['w']) player.y -= player.speed;
401
+ if (keys['arrowdown'] || keys['s']) player.y += player.speed;
402
+ if (keys['arrowleft'] || keys['a']) player.x -= player.speed;
403
+ if (keys['arrowright'] || keys['d']) player.x += player.speed;
404
+
405
+ // Keep player in bounds
406
+ player.x = Math.max(player.size, Math.min(canvas.width - player.size, player.x));
407
+ player.y = Math.max(player.size, Math.min(canvas.height - player.size, player.y));
408
+
409
+ // Check if in territory
410
+ const gridX = Math.floor(player.x / 2) * 2;
411
+ const gridY = Math.floor(player.y / 2) * 2;
412
+ player.inTerritory = territory.has(`${gridX},${gridY}`);
413
+
414
+ // Handle trail
415
+ if (!player.inTerritory) {
416
+ player.trail.push({x: player.x, y: player.y});
417
+ if (player.trail.length > 100) {
418
+ player.trail.shift();
419
+ }
420
+ } else if (player.trail.length > 0) {
421
+ // Claim new territory
422
+ claimTerritory();
423
+ player.trail = [];
424
+ }
425
+
426
+ // Auto-fire at enemies
427
+ autoFire();
428
+ }
429
+
430
+ function autoFire() {
431
+ const currentTime = Date.now();
432
+ if (currentTime - player.lastShot < player.fireRate) return;
433
+
434
+ // Find nearest enemy within range
435
+ let nearestEnemy = null;
436
+ let nearestDistance = player.range;
437
+
438
+ for(let enemy of enemies) {
439
+ const dx = enemy.x - player.x;
440
+ const dy = enemy.y - player.y;
441
+ const distance = Math.sqrt(dx * dx + dy * dy);
442
+
443
+ if (distance < nearestDistance) {
444
+ nearestEnemy = enemy;
445
+ nearestDistance = distance;
446
+ }
447
+ }
448
+
449
+ if (nearestEnemy) {
450
+ // Calculate direction to enemy
451
+ const dx = nearestEnemy.x - player.x;
452
+ const dy = nearestEnemy.y - player.y;
453
+ const angle = Math.atan2(dy, dx);
454
+
455
+ // Create bullet
456
+ bullets.push({
457
+ x: player.x,
458
+ y: player.y,
459
+ dx: Math.cos(angle) * 8,
460
+ dy: Math.sin(angle) * 8,
461
+ size: 3,
462
+ life: 60
463
+ });
464
+
465
+ player.lastShot = currentTime;
466
+ }
467
+ }
468
+
469
+ function updateBullets() {
470
+ for(let i = bullets.length - 1; i >= 0; i--) {
471
+ const bullet = bullets[i];
472
+ bullet.x += bullet.dx;
473
+ bullet.y += bullet.dy;
474
+ bullet.life--;
475
+
476
+ // Remove bullets that are out of bounds or expired
477
+ if (bullet.x < 0 || bullet.x > canvas.width ||
478
+ bullet.y < 0 || bullet.y > canvas.height ||
479
+ bullet.life <= 0) {
480
+ bullets.splice(i, 1);
481
+ continue;
482
+ }
483
+
484
+ // Check bullet collision with enemies
485
+ for(let j = enemies.length - 1; j >= 0; j--) {
486
+ const enemy = enemies[j];
487
+ const dx = bullet.x - enemy.x;
488
+ const dy = bullet.y - enemy.y;
489
+ const distance = Math.sqrt(dx * dx + dy * dy);
490
+
491
+ if (distance < bullet.size + enemy.size) {
492
+ // Hit enemy
493
+ enemy.health--;
494
+ bullets.splice(i, 1);
495
+
496
+ if (enemy.health <= 0) {
497
+ // Enemy defeated - spawn double the enemies!
498
+ killCount++;
499
+ const defeatedEnemy = enemies.splice(j, 1)[0];
500
+
501
+ // Spawn 2 new enemies to replace the defeated one
502
+ for(let k = 0; k < 2; k++) {
503
+ let x, y;
504
+ do {
505
+ x = Math.random() * (canvas.width - 60) + 30;
506
+ y = Math.random() * (canvas.height - 60) + 30;
507
+ } while(Math.abs(x - player.x) < 100);
508
+
509
+ enemies.push({
510
+ x: x,
511
+ y: y,
512
+ size: 10 + Math.random() * 6,
513
+ speed: 1.2 + Math.random() * 1.8 + level * 0.15,
514
+ color: `hsl(${Math.random() * 360}, 70%, 60%)`,
515
+ direction: Math.random() * Math.PI * 2,
516
+ changeDirection: 0,
517
+ health: 1
518
+ });
519
+ }
520
+ }
521
+ break;
522
+ }
523
+ }
524
+ }
525
+ }
526
+
527
+ function claimTerritory() {
528
+ // Simple flood fill from trail
529
+ const newClaimed = new Set();
530
+
531
+ // Add trail points to territory
532
+ for(let point of player.trail) {
533
+ const gridX = Math.floor(point.x / 2) * 2;
534
+ const gridY = Math.floor(point.y / 2) * 2;
535
+ territory.add(`${gridX},${gridY}`);
536
+ newClaimed.add(`${gridX},${gridY}`);
537
+ }
538
+
539
+ // Fill enclosed areas (simplified)
540
+ for(let point of player.trail) {
541
+ const startX = Math.floor(point.x / 2) * 2;
542
+ const startY = Math.floor(point.y / 2) * 2;
543
+
544
+ // Fill in a small area around the trail
545
+ for(let dx = -20; dx <= 20; dx += 2) {
546
+ for(let dy = -20; dy <= 20; dy += 2) {
547
+ const x = startX + dx;
548
+ const y = startY + dy;
549
+ if (x >= 0 && x < canvas.width && y >= 0 && y < canvas.height) {
550
+ territory.add(`${x},${y}`);
551
+ claimedArea.add(`${x},${y}`);
552
+ }
553
+ }
554
+ }
555
+ }
556
+ }
557
+
558
+ function updateEnemies() {
559
+ for(let enemy of enemies) {
560
+ // Simple AI movement
561
+ enemy.changeDirection--;
562
+ if (enemy.changeDirection <= 0) {
563
+ enemy.direction = Math.random() * Math.PI * 2;
564
+ enemy.changeDirection = 60 + Math.random() * 120;
565
+ }
566
+
567
+ enemy.x += Math.cos(enemy.direction) * enemy.speed;
568
+ enemy.y += Math.sin(enemy.direction) * enemy.speed;
569
+
570
+ // Bounce off walls
571
+ if (enemy.x <= 0 || enemy.x >= canvas.width) {
572
+ enemy.direction = Math.PI - enemy.direction;
573
+ enemy.x = Math.max(0, Math.min(canvas.width, enemy.x));
574
+ }
575
+ if (enemy.y <= 0 || enemy.y >= canvas.height) {
576
+ enemy.direction = -enemy.direction;
577
+ enemy.y = Math.max(0, Math.min(canvas.height, enemy.y));
578
+ }
579
+
580
+ // Check collision with player
581
+ const dx = enemy.x - player.x;
582
+ const dy = enemy.y - player.y;
583
+ const distance = Math.sqrt(dx * dx + dy * dy);
584
+
585
+ if (distance < enemy.size + player.size) {
586
+ gameOver();
587
+ return;
588
+ }
589
+
590
+ // Check collision with trail
591
+ for(let point of player.trail) {
592
+ const trailDx = enemy.x - point.x;
593
+ const trailDy = enemy.y - point.y;
594
+ const trailDistance = Math.sqrt(trailDx * trailDx + trailDy * trailDy);
595
+ if (trailDistance < enemy.size + 5) {
596
+ gameOver();
597
+ return;
598
+ }
599
+ }
600
+ }
601
+ }
602
+
603
+ function render() {
604
+ // Clear canvas with ocean gradient
605
+ const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
606
+ gradient.addColorStop(0, '#001a33');
607
+ gradient.addColorStop(1, '#002d5a');
608
+ ctx.fillStyle = gradient;
609
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
610
+
611
+ // Draw bubbles
612
+ for(let i = 0; i < 20; i++) {
613
+ const x = (Date.now() * 0.01 + i * 50) % canvas.width;
614
+ const y = (Date.now() * 0.02 + i * 30) % canvas.height;
615
+ ctx.fillStyle = 'rgba(100, 200, 255, 0.1)';
616
+ ctx.beginPath();
617
+ ctx.arc(x, y, 3 + Math.sin(Date.now() * 0.01 + i) * 2, 0, Math.PI * 2);
618
+ ctx.fill();
619
+ }
620
+
621
+ // Draw claimed territory
622
+ ctx.fillStyle = 'rgba(0, 204, 255, 0.3)';
623
+ for(let pos of claimedArea) {
624
+ const [x, y] = pos.split(',').map(Number);
625
+ ctx.fillRect(x, y, 2, 2);
626
+ }
627
+
628
+ // Draw trail
629
+ if (player.trail.length > 0) {
630
+ ctx.strokeStyle = '#ffff00';
631
+ ctx.lineWidth = 3;
632
+ ctx.beginPath();
633
+ ctx.moveTo(player.trail[0].x, player.trail[0].y);
634
+ for(let i = 1; i < player.trail.length; i++) {
635
+ ctx.lineTo(player.trail[i].x, player.trail[i].y);
636
+ }
637
+ ctx.stroke();
638
+ }
639
+
640
+ // Draw bullets
641
+ ctx.fillStyle = '#ffff00';
642
+ for(let bullet of bullets) {
643
+ ctx.beginPath();
644
+ ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
645
+ ctx.fill();
646
+
647
+ // Add glow effect
648
+ ctx.shadowColor = '#ffff00';
649
+ ctx.shadowBlur = 10;
650
+ ctx.beginPath();
651
+ ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
652
+ ctx.fill();
653
+ ctx.shadowBlur = 0;
654
+ }
655
+ for(let enemy of enemies) {
656
+ ctx.fillStyle = enemy.color;
657
+ ctx.beginPath();
658
+ ctx.arc(enemy.x, enemy.y, enemy.size, 0, Math.PI * 2);
659
+ ctx.fill();
660
+
661
+ // Fish details
662
+ ctx.fillStyle = 'white';
663
+ ctx.beginPath();
664
+ ctx.arc(enemy.x - enemy.size * 0.3, enemy.y - enemy.size * 0.3, enemy.size * 0.2, 0, Math.PI * 2);
665
+ ctx.fill();
666
+ }
667
+
668
+ // Draw player
669
+ ctx.fillStyle = player.inTerritory ? player.color : '#ffff00';
670
+ ctx.beginPath();
671
+ ctx.arc(player.x, player.y, player.size, 0, Math.PI * 2);
672
+ ctx.fill();
673
+
674
+ // Player fish details
675
+ ctx.fillStyle = 'white';
676
+ ctx.beginPath();
677
+ ctx.arc(player.x - player.size * 0.3, player.y - player.size * 0.3, player.size * 0.3, 0, Math.PI * 2);
678
+ ctx.fill();
679
+ ctx.fillStyle = 'black';
680
+ ctx.beginPath();
681
+ ctx.arc(player.x - player.size * 0.3, player.y - player.size * 0.3, player.size * 0.15, 0, Math.PI * 2);
682
+ ctx.fill();
683
+
684
+ // Draw firing range indicator
685
+ ctx.strokeStyle = 'rgba(255, 255, 0, 0.2)';
686
+ ctx.lineWidth = 2;
687
+ ctx.beginPath();
688
+ ctx.arc(player.x, player.y, player.range, 0, Math.PI * 2);
689
+ ctx.stroke();
690
+ }
691
+
692
+ function updateUI() {
693
+ const territoryPercent = Math.floor((claimedArea.size / (canvas.width * canvas.height / 4)) * 100);
694
+ document.getElementById('territoryScore').textContent = territoryPercent;
695
+ document.getElementById('timeScore').textContent = Math.floor(gameTime);
696
+ document.getElementById('enemyCount').textContent = enemies.length;
697
+ document.getElementById('killCount').textContent = killCount;
698
+
699
+ // Level up
700
+ if (territoryPercent >= level * 15) {
701
+ level++;
702
+ spawnEnemies();
703
+ }
704
+ }
705
+
706
+ function gameLoop(currentTime) {
707
+ if (!gameRunning) return;
708
+
709
+ const deltaTime = currentTime - lastTime;
710
+ lastTime = currentTime;
711
+ gameTime += deltaTime / 1000;
712
+
713
+ updatePlayer();
714
+ updateBullets();
715
+ updateEnemies();
716
+ render();
717
+ updateUI();
718
+
719
+ requestAnimationFrame(gameLoop);
720
+ }
721
+ </script>
722
+ </body>
723
+ </html>