Davi111 commited on
Commit
2bc517b
·
verified ·
1 Parent(s): c193c4f

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +731 -365
  2. prompts.txt +2 -1
index.html CHANGED
@@ -3,19 +3,19 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Free Fire 2D</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
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;800&display=swap');
11
 
12
  body {
13
- font-family: 'Poppins', sans-serif;
14
- background-color: #0f172a;
15
- color: white;
16
- overflow: hidden;
17
  margin: 0;
18
  padding: 0;
 
 
 
19
  }
20
 
21
  #gameContainer {
@@ -23,60 +23,46 @@
23
  width: 100vw;
24
  height: 100vh;
25
  overflow: hidden;
26
- background-color: #1e293b;
27
- background-image:
28
- linear-gradient(#1e293b 1px, transparent 1px),
29
- linear-gradient(90deg, #1e293b 1px, transparent 1px);
30
- background-size: 40px 40px;
31
  }
32
 
33
- #player {
34
  position: absolute;
35
- width: 40px;
36
- height: 40px;
37
- background-color: #ea580c;
38
- border-radius: 50%;
39
- z-index: 10;
40
- box-shadow: 0 0 10px rgba(234, 88, 12, 0.7);
41
  }
42
 
43
- .enemy {
44
  position: absolute;
45
- width: 30px;
46
- height: 30px;
47
- background-color: #dc2626;
48
- border-radius: 50%;
49
- z-index: 5;
 
 
50
  }
51
 
52
- .bullet {
 
53
  position: absolute;
54
- width: 8px;
55
- height: 8px;
56
- background-color: #f59e0b;
57
- border-radius: 50%;
58
- z-index: 8;
59
  }
60
 
61
- .weapon {
62
- position: absolute;
63
- width: 20px;
64
- height: 10px;
65
- background-color: #64748b;
66
- border-radius: 3px;
67
  }
68
 
69
- .health-pack {
70
- position: absolute;
71
- width: 20px;
72
- height: 20px;
73
- background-color: #10b981;
74
- border-radius: 50%;
75
- display: flex;
76
- align-items: center;
77
- justify-content: center;
78
- color: white;
79
- font-size: 10px;
80
  }
81
 
82
  #uiContainer {
@@ -86,41 +72,53 @@
86
  width: 100%;
87
  height: 100%;
88
  pointer-events: none;
89
- z-index: 20;
90
  }
91
 
92
  #healthBar {
93
  position: absolute;
94
- top: 20px;
95
  left: 20px;
96
  width: 200px;
97
- height: 20px;
98
- background-color: #334155;
99
- border-radius: 10px;
 
100
  overflow: hidden;
101
  }
102
 
103
  #healthFill {
104
  height: 100%;
105
  width: 100%;
106
- background-color: #10b981;
107
  transition: width 0.3s;
108
  }
109
 
110
  #ammoCount {
111
  position: absolute;
112
- top: 50px;
113
- left: 20px;
114
- font-size: 16px;
115
  color: white;
 
116
  }
117
 
118
  #scoreDisplay {
119
  position: absolute;
120
  top: 20px;
 
 
 
 
 
 
 
 
 
121
  right: 20px;
122
  font-size: 24px;
123
  color: white;
 
124
  }
125
 
126
  #gameOverScreen {
@@ -134,7 +132,7 @@
134
  flex-direction: column;
135
  justify-content: center;
136
  align-items: center;
137
- z-index: 30;
138
  }
139
 
140
  #startScreen {
@@ -143,164 +141,259 @@
143
  left: 0;
144
  width: 100%;
145
  height: 100%;
146
- background-color: rgba(15, 23, 42, 0.9);
147
  display: flex;
148
  flex-direction: column;
149
  justify-content: center;
150
  align-items: center;
151
- z-index: 40;
152
  }
153
 
154
  .btn {
155
- background-color: #ea580c;
156
  color: white;
157
  border: none;
158
- padding: 12px 24px;
159
  font-size: 18px;
160
- border-radius: 8px;
161
  cursor: pointer;
162
- margin-top: 20px;
163
- font-weight: bold;
164
- box-shadow: 0 0 15px rgba(234, 88, 12, 0.5);
 
 
165
  transition: all 0.3s;
166
  }
167
 
168
  .btn:hover {
169
- background-color: #c2410c;
170
- transform: translateY(-2px);
171
- box-shadow: 0 0 20px rgba(234, 88, 12, 0.8);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
 
174
- .controls {
175
  position: absolute;
176
  bottom: 20px;
177
  width: 100%;
178
- display: flex;
179
  justify-content: space-between;
180
  padding: 0 20px;
181
  box-sizing: border-box;
182
  }
183
 
184
- .control-btn {
185
- width: 60px;
186
- height: 60px;
187
- background-color: rgba(30, 41, 59, 0.7);
188
  border-radius: 50%;
189
  display: flex;
190
  align-items: center;
191
  justify-content: center;
192
  color: white;
193
  font-size: 24px;
194
- cursor: pointer;
195
  pointer-events: auto;
196
  user-select: none;
197
  touch-action: manipulation;
198
  }
199
 
200
- #joystick {
 
 
 
 
201
  position: relative;
202
- width: 80px;
203
- height: 80px;
204
- background-color: rgba(30, 41, 59, 0.5);
205
  border-radius: 50%;
206
  }
207
 
208
- #joystickKnob {
209
  position: absolute;
210
- width: 40px;
211
- height: 40px;
212
- background-color: rgba(234, 88, 12, 0.7);
213
  border-radius: 50%;
214
- top: 20px;
215
- left: 20px;
216
  }
217
 
218
- #shootBtn {
219
- background-color: rgba(220, 38, 38, 0.7);
 
 
220
  }
221
  </style>
222
  </head>
223
  <body>
224
  <div id="gameContainer">
225
- <div id="player"></div>
226
- <!-- Enemies, bullets, and items will be added dynamically -->
 
 
227
 
228
  <div id="uiContainer">
229
  <div id="healthBar">
230
  <div id="healthFill"></div>
231
  </div>
232
- <div id="ammoCount">Ammo: 30/30</div>
233
- <div id="scoreDisplay">Score: 0</div>
 
 
 
 
234
 
235
- <div class="controls">
236
- <div id="joystick">
237
- <div id="joystickKnob"></div>
238
  </div>
239
- <div id="shootBtn" class="control-btn">
240
  <i class="fas fa-fire"></i>
241
  </div>
242
  </div>
243
  </div>
244
 
245
  <div id="gameOverScreen">
246
- <h1 class="text-4xl font-bold text-red-500 mb-4">GAME OVER</h1>
247
- <p class="text-xl text-white mb-8">Your score: <span id="finalScore">0</span></p>
248
- <button id="restartBtn" class="btn">Play Again</button>
 
249
  </div>
250
 
251
  <div id="startScreen">
252
- <h1 class="text-5xl font-bold text-orange-500 mb-4">FREE FIRE 2D</h1>
253
- <p class="text-xl text-gray-300 mb-8">Survive as long as you can!</p>
254
- <button id="startBtn" class="btn">Start Game</button>
255
- <div class="mt-8 text-gray-400 text-center">
256
- <p class="mb-2">Controls:</p>
257
- <p>Move: Drag the joystick</p>
258
- <p>Shoot: Tap the fire button</p>
 
 
259
  </div>
260
  </div>
261
  </div>
262
 
263
  <script>
264
  // Game variables
265
- const player = document.getElementById('player');
266
- const gameContainer = document.getElementById('gameContainer');
267
  const healthFill = document.getElementById('healthFill');
268
  const ammoCount = document.getElementById('ammoCount');
269
  const scoreDisplay = document.getElementById('scoreDisplay');
 
270
  const gameOverScreen = document.getElementById('gameOverScreen');
271
  const finalScore = document.getElementById('finalScore');
272
  const startScreen = document.getElementById('startScreen');
273
  const startBtn = document.getElementById('startBtn');
274
  const restartBtn = document.getElementById('restartBtn');
275
- const joystick = document.getElementById('joystick');
276
- const joystickKnob = document.getElementById('joystickKnob');
 
 
277
  const shootBtn = document.getElementById('shootBtn');
 
 
278
 
279
- let gameWidth = gameContainer.clientWidth;
280
- let gameHeight = gameContainer.clientHeight;
281
- let playerX = gameWidth / 2;
282
- let playerY = gameHeight / 2;
283
- let playerSpeed = 5;
 
 
284
  let health = 100;
285
- let ammo = 30;
286
- let maxAmmo = 30;
287
  let score = 0;
288
  let gameRunning = false;
289
- let enemies = [];
290
- let bullets = [];
291
- let weapons = [];
292
- let healthPacks = [];
293
  let lastShotTime = 0;
294
- let shootCooldown = 300; // ms
295
- let enemySpawnRate = 2000; // ms
296
  let lastEnemySpawn = 0;
297
- let joystickActive = false;
298
- let joystickAngle = 0;
299
- let joystickDistance = 0;
 
300
 
301
- // Initialize player position
302
- player.style.left = playerX + 'px';
303
- player.style.top = playerY + 'px';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
  // Start screen
306
  startBtn.addEventListener('click', startGame);
@@ -308,47 +401,135 @@
308
  // Restart game
309
  restartBtn.addEventListener('click', startGame);
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  // Touch controls for mobile
312
- joystick.addEventListener('touchstart', handleJoystickStart);
313
- joystick.addEventListener('touchmove', handleJoystickMove);
314
- joystick.addEventListener('touchend', handleJoystickEnd);
 
315
 
316
- // Mouse controls for desktop
317
- joystick.addEventListener('mousedown', handleJoystickStart);
318
- document.addEventListener('mousemove', handleJoystickMove);
319
- document.addEventListener('mouseup', handleJoystickEnd);
 
 
 
 
 
320
 
321
- // Shoot button
322
- shootBtn.addEventListener('touchstart', shoot);
323
- shootBtn.addEventListener('mousedown', shoot);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
  function startGame() {
326
  // Reset game state
327
  health = 100;
328
- ammo = maxAmmo;
329
  score = 0;
 
 
 
330
  enemies = [];
331
- bullets = [];
332
- weapons = [];
333
- healthPacks = [];
 
 
 
 
 
334
 
335
  // Update UI
336
  updateHealth();
337
  updateAmmo();
338
  updateScore();
339
-
340
- // Clear all existing game elements
341
- document.querySelectorAll('.enemy, .bullet, .weapon, .health-pack').forEach(el => el.remove());
342
 
343
  // Hide screens
344
  gameOverScreen.style.display = 'none';
345
  startScreen.style.display = 'none';
346
 
347
- // Reset player position
348
- playerX = gameWidth / 2;
349
- playerY = gameHeight / 2;
350
- player.style.left = playerX + 'px';
351
- player.style.top = playerY + 'px';
352
 
353
  // Start game loop
354
  gameRunning = true;
@@ -361,6 +542,42 @@
361
 
362
  const now = Date.now();
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  // Spawn enemies
365
  if (now - lastEnemySpawn > enemySpawnRate) {
366
  spawnEnemy();
@@ -372,203 +589,390 @@
372
  }
373
  }
374
 
375
- // Move player if joystick is active
376
- if (joystickActive) {
377
- const moveX = Math.cos(joystickAngle) * playerSpeed * (joystickDistance / 40);
378
- const moveY = Math.sin(joystickAngle) * playerSpeed * (joystickDistance / 40);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
- playerX = Math.max(20, Math.min(gameWidth - 20, playerX + moveX));
381
- playerY = Math.max(20, Math.min(gameHeight - 20, playerY + moveY));
 
 
 
 
382
 
383
- player.style.left = playerX + 'px';
384
- player.style.top = playerY + 'px';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  }
386
 
387
- // Move enemies
388
- enemies.forEach(enemy => {
389
- const enemyX = parseFloat(enemy.style.left) + enemy.dataset.speedX;
390
- const enemyY = parseFloat(enemy.style.top) + enemy.dataset.speedY;
 
 
 
 
 
 
 
 
 
 
391
 
392
- // Keep enemy in bounds
393
- if (enemyX < 15 || enemyX > gameWidth - 15) {
394
- enemy.dataset.speedX *= -1;
395
- }
396
- if (enemyY < 15 || enemyY > gameHeight - 15) {
397
- enemy.dataset.speedY *= -1;
 
 
 
398
  }
399
 
400
- enemy.style.left = enemyX + 'px';
401
- enemy.style.top = enemyY + 'px';
 
 
402
 
403
- // Check collision with player
404
- if (checkCollision(player, enemy)) {
405
- takeDamage(10);
 
 
 
 
 
 
 
 
406
  }
407
- });
408
-
409
- // Move bullets
410
- bullets.forEach((bullet, index) => {
411
- const bulletX = parseFloat(bullet.style.left) + bullet.dataset.speedX;
412
- const bulletY = parseFloat(bullet.style.top) + bullet.dataset.speedY;
413
 
414
- bullet.style.left = bulletX + 'px';
415
- bullet.style.top = bulletY + 'px';
 
416
 
417
- // Remove bullet if out of bounds
418
- if (bulletX < 0 || bulletX > gameWidth || bulletY < 0 || bulletY > gameHeight) {
419
- bullet.remove();
420
- bullets.splice(index, 1);
421
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  }
423
 
424
- // Check bullet collision with enemies
425
- enemies.forEach((enemy, enemyIndex) => {
426
- if (checkCollision(bullet, enemy)) {
427
- // Remove both bullet and enemy
428
- bullet.remove();
429
- bullets.splice(index, 1);
430
-
431
- enemy.remove();
432
- enemies.splice(enemyIndex, 1);
433
-
434
- // Increase score
435
- score += 1;
436
- updateScore();
437
-
438
- // Random chance to drop weapon or health pack
439
- if (Math.random() < 0.2) {
440
- if (Math.random() < 0.5) {
441
- spawnWeapon(parseFloat(enemy.style.left), parseFloat(enemy.style.top));
442
- } else {
443
- spawnHealthPack(parseFloat(enemy.style.left), parseFloat(enemy.style.top));
444
- }
445
- }
446
  }
447
- });
448
- });
449
-
450
- // Check weapon pickups
451
- weapons.forEach((weapon, index) => {
452
- if (checkCollision(player, weapon)) {
453
- // Increase ammo
454
- ammo = maxAmmo;
455
- updateAmmo();
456
 
457
- weapon.remove();
458
- weapons.splice(index, 1);
459
- }
460
- });
461
-
462
- // Check health pack pickups
463
- healthPacks.forEach((healthPack, index) => {
464
- if (checkCollision(player, healthPack)) {
465
- // Increase health
466
- health = Math.min(100, health + 25);
467
- updateHealth();
468
 
469
- healthPack.remove();
470
- healthPacks.splice(index, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  }
472
- });
473
-
474
- // Continue game loop
475
- requestAnimationFrame(gameLoop);
476
  }
477
 
478
- function spawnEnemy() {
479
- const enemy = document.createElement('div');
480
- enemy.className = 'enemy';
481
-
482
- // Random position at edges
483
- let x, y;
484
- if (Math.random() < 0.5) {
485
- x = Math.random() < 0.5 ? 0 : gameWidth;
486
- y = Math.random() * gameHeight;
487
- } else {
488
- x = Math.random() * gameWidth;
489
- y = Math.random() < 0.5 ? 0 : gameHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  }
491
-
492
- enemy.style.left = x + 'px';
493
- enemy.style.top = y + 'px';
494
-
495
- // Random speed (toward player)
496
- const angle = Math.atan2(playerY - y, playerX - x);
497
- const speed = 1 + Math.random() * 2;
498
-
499
- enemy.dataset.speedX = Math.cos(angle) * speed;
500
- enemy.dataset.speedY = Math.sin(angle) * speed;
501
-
502
- gameContainer.appendChild(enemy);
503
- enemies.push(enemy);
504
  }
505
 
506
- function spawnWeapon(x, y) {
507
- const weapon = document.createElement('div');
508
- weapon.className = 'weapon';
509
- weapon.style.left = x + 'px';
510
- weapon.style.top = y + 'px';
 
511
 
512
- gameContainer.appendChild(weapon);
513
- weapons.push(weapon);
514
- }
515
-
516
- function spawnHealthPack(x, y) {
517
- const healthPack = document.createElement('div');
518
- healthPack.className = 'health-pack';
519
- healthPack.style.left = x + 'px';
520
- healthPack.style.top = y + 'px';
521
- healthPack.innerHTML = '<i class="fas fa-heart"></i>';
522
 
523
- gameContainer.appendChild(healthPack);
524
- healthPacks.push(healthPack);
 
 
 
 
 
 
 
 
525
  }
526
 
527
  function shoot() {
528
  const now = Date.now();
529
- if (now - lastShotTime < shootCooldown || ammo <= 0) return;
 
 
 
 
 
 
530
 
531
  lastShotTime = now;
532
- ammo--;
533
  updateAmmo();
534
 
535
- const bullet = document.createElement('div');
536
- bullet.className = 'bullet';
 
 
 
 
 
 
 
 
537
 
538
- // Start bullet at player position
539
- bullet.style.left = playerX + 'px';
540
- bullet.style.top = playerY + 'px';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
541
 
542
- // Shoot toward mouse/touch position
543
- const angle = joystickActive ? joystickAngle : Math.random() * Math.PI * 2;
544
- const speed = 10;
 
 
 
 
 
545
 
546
- bullet.dataset.speedX = Math.cos(angle) * speed;
547
- bullet.dataset.speedY = Math.sin(angle) * speed;
 
548
 
549
- gameContainer.appendChild(bullet);
550
- bullets.push(bullet);
551
 
552
- // Reload if out of ammo
553
- if (ammo <= 0) {
554
- setTimeout(() => {
555
- ammo = maxAmmo;
 
 
 
 
 
556
  updateAmmo();
557
- }, 1000);
558
- }
 
 
559
  }
560
 
561
  function takeDamage(amount) {
562
  health -= amount;
563
  updateHealth();
564
 
565
- // Flash player when hit
566
- player.style.backgroundColor = 'white';
567
- setTimeout(() => {
568
- player.style.backgroundColor = '#ea580c';
569
- }, 100);
570
-
571
- // Check if player died
572
  if (health <= 0) {
573
  health = 0;
574
  updateHealth();
@@ -577,24 +981,28 @@
577
  }
578
 
579
  function updateHealth() {
580
- healthFill.style.width = health + '%';
581
 
582
  // Change color based on health
583
- if (health > 50) {
584
- healthFill.style.backgroundColor = '#10b981';
585
- } else if (health > 20) {
586
- healthFill.style.backgroundColor = '#f59e0b';
587
  } else {
588
- healthFill.style.backgroundColor = '#dc2626';
589
  }
590
  }
591
 
592
  function updateAmmo() {
593
- ammoCount.textContent = `Ammo: ${ammo}/${maxAmmo}`;
594
  }
595
 
596
  function updateScore() {
597
- scoreDisplay.textContent = `Score: ${score}`;
 
 
 
 
598
  }
599
 
600
  function gameOver() {
@@ -603,67 +1011,25 @@
603
  gameOverScreen.style.display = 'flex';
604
  }
605
 
606
- function checkCollision(element1, element2) {
607
- const rect1 = element1.getBoundingClientRect();
608
- const rect2 = element2.getBoundingClientRect();
609
 
610
- return !(
611
- rect1.right < rect2.left ||
612
- rect1.left > rect2.right ||
613
- rect1.bottom < rect2.top ||
614
- rect1.top > rect2.bottom
615
- );
616
  }
617
 
618
- function handleJoystickStart(e) {
619
- e.preventDefault();
620
- joystickActive = true;
621
- handleJoystickMove(e);
622
- }
623
-
624
- function handleJoystickMove(e) {
625
- if (!joystickActive) return;
626
-
627
- e.preventDefault();
628
-
629
- // Get joystick position
630
- const joystickRect = joystick.getBoundingClientRect();
631
- const joystickCenterX = joystickRect.left + joystickRect.width / 2;
632
- const joystickCenterY = joystickRect.top + joystickRect.height / 2;
633
-
634
- // Get touch/mouse position
635
- let clientX, clientY;
636
- if (e.touches) {
637
- clientX = e.touches[0].clientX;
638
- clientY = e.touches[0].clientY;
639
- } else {
640
- clientX = e.clientX;
641
- clientY = e.clientY;
642
- }
643
-
644
- // Calculate angle and distance
645
- const dx = clientX - joystickCenterX;
646
- const dy = clientY - joystickCenterY;
647
- joystickAngle = Math.atan2(dy, dx);
648
- joystickDistance = Math.min(40, Math.sqrt(dx * dx + dy * dy));
649
-
650
- // Move joystick knob
651
- const knobX = Math.cos(joystickAngle) * joystickDistance;
652
- const knobY = Math.sin(joystickAngle) * joystickDistance;
653
-
654
- joystickKnob.style.transform = `translate(${knobX}px, ${knobY}px)`;
655
- }
656
-
657
- function handleJoystickEnd(e) {
658
- e.preventDefault();
659
- joystickActive = false;
660
- joystickKnob.style.transform = 'translate(0, 0)';
661
  }
662
 
663
  // Handle window resize
664
  window.addEventListener('resize', () => {
665
- gameWidth = gameContainer.clientWidth;
666
- gameHeight = gameContainer.clientHeight;
 
 
667
  });
668
  </script>
669
  <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=Davi111/games" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>2D FPS Game</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
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
11
 
12
  body {
13
+ font-family: 'Press Start 2P', cursive;
 
 
 
14
  margin: 0;
15
  padding: 0;
16
+ overflow: hidden;
17
+ background-color: #111;
18
+ color: white;
19
  }
20
 
21
  #gameContainer {
 
23
  width: 100vw;
24
  height: 100vh;
25
  overflow: hidden;
26
+ perspective: 1000px;
 
 
 
 
27
  }
28
 
29
+ #gameCanvas {
30
  position: absolute;
31
+ width: 100%;
32
+ height: 100%;
33
+ background-color: #222;
34
+ image-rendering: pixelated;
 
 
35
  }
36
 
37
+ #crosshair {
38
  position: absolute;
39
+ top: 50%;
40
+ left: 50%;
41
+ transform: translate(-50%, -50%);
42
+ width: 20px;
43
+ height: 20px;
44
+ pointer-events: none;
45
+ z-index: 100;
46
  }
47
 
48
+ #crosshair::before, #crosshair::after {
49
+ content: '';
50
  position: absolute;
51
+ background-color: rgba(255, 255, 255, 0.8);
 
 
 
 
52
  }
53
 
54
+ #crosshair::before {
55
+ width: 2px;
56
+ height: 12px;
57
+ top: 4px;
58
+ left: 9px;
 
59
  }
60
 
61
+ #crosshair::after {
62
+ width: 12px;
63
+ height: 2px;
64
+ top: 9px;
65
+ left: 4px;
 
 
 
 
 
 
66
  }
67
 
68
  #uiContainer {
 
72
  width: 100%;
73
  height: 100%;
74
  pointer-events: none;
75
+ z-index: 50;
76
  }
77
 
78
  #healthBar {
79
  position: absolute;
80
+ bottom: 20px;
81
  left: 20px;
82
  width: 200px;
83
+ height: 30px;
84
+ background-color: rgba(70, 0, 0, 0.7);
85
+ border: 3px solid #444;
86
+ border-radius: 5px;
87
  overflow: hidden;
88
  }
89
 
90
  #healthFill {
91
  height: 100%;
92
  width: 100%;
93
+ background-color: #f00;
94
  transition: width 0.3s;
95
  }
96
 
97
  #ammoCount {
98
  position: absolute;
99
+ bottom: 20px;
100
+ right: 20px;
101
+ font-size: 24px;
102
  color: white;
103
+ text-shadow: 2px 2px 0 #000;
104
  }
105
 
106
  #scoreDisplay {
107
  position: absolute;
108
  top: 20px;
109
+ left: 20px;
110
+ font-size: 24px;
111
+ color: white;
112
+ text-shadow: 2px 2px 0 #000;
113
+ }
114
+
115
+ #weaponDisplay {
116
+ position: absolute;
117
+ bottom: 70px;
118
  right: 20px;
119
  font-size: 24px;
120
  color: white;
121
+ text-shadow: 2px 2px 0 #000;
122
  }
123
 
124
  #gameOverScreen {
 
132
  flex-direction: column;
133
  justify-content: center;
134
  align-items: center;
135
+ z-index: 200;
136
  }
137
 
138
  #startScreen {
 
141
  left: 0;
142
  width: 100%;
143
  height: 100%;
144
+ background-color: rgba(0, 0, 0, 0.9);
145
  display: flex;
146
  flex-direction: column;
147
  justify-content: center;
148
  align-items: center;
149
+ z-index: 150;
150
  }
151
 
152
  .btn {
153
+ background-color: #f00;
154
  color: white;
155
  border: none;
156
+ padding: 15px 30px;
157
  font-size: 18px;
158
+ border-radius: 5px;
159
  cursor: pointer;
160
+ margin-top: 30px;
161
+ font-family: 'Press Start 2P', cursive;
162
+ text-transform: uppercase;
163
+ letter-spacing: 2px;
164
+ box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
165
  transition: all 0.3s;
166
  }
167
 
168
  .btn:hover {
169
+ background-color: #c00;
170
+ transform: translateY(-3px);
171
+ box-shadow: 0 0 20px rgba(255, 0, 0, 0.8);
172
+ }
173
+
174
+ #bloodEffect {
175
+ position: absolute;
176
+ top: 0;
177
+ left: 0;
178
+ width: 100%;
179
+ height: 100%;
180
+ background-color: rgba(255, 0, 0, 0);
181
+ pointer-events: none;
182
+ z-index: 60;
183
+ transition: background-color 0.3s;
184
+ }
185
+
186
+ #reloadIndicator {
187
+ position: absolute;
188
+ bottom: 120px;
189
+ right: 20px;
190
+ width: 100px;
191
+ height: 10px;
192
+ background-color: rgba(255, 255, 255, 0.3);
193
+ border-radius: 5px;
194
+ overflow: hidden;
195
+ display: none;
196
+ }
197
+
198
+ #reloadFill {
199
+ height: 100%;
200
+ width: 0%;
201
+ background-color: #ff0;
202
+ transition: width 0.1s linear;
203
+ }
204
+
205
+ #enemyHitEffect {
206
+ position: absolute;
207
+ top: 0;
208
+ left: 0;
209
+ width: 100%;
210
+ height: 100%;
211
+ background-color: rgba(255, 255, 255, 0);
212
+ pointer-events: none;
213
+ z-index: 60;
214
+ transition: background-color 0.1s;
215
  }
216
 
217
+ #mobileControls {
218
  position: absolute;
219
  bottom: 20px;
220
  width: 100%;
221
+ display: none;
222
  justify-content: space-between;
223
  padding: 0 20px;
224
  box-sizing: border-box;
225
  }
226
 
227
+ .mobile-btn {
228
+ width: 70px;
229
+ height: 70px;
230
+ background-color: rgba(255, 255, 255, 0.2);
231
  border-radius: 50%;
232
  display: flex;
233
  align-items: center;
234
  justify-content: center;
235
  color: white;
236
  font-size: 24px;
 
237
  pointer-events: auto;
238
  user-select: none;
239
  touch-action: manipulation;
240
  }
241
 
242
+ #shootBtn {
243
+ background-color: rgba(255, 0, 0, 0.5);
244
+ }
245
+
246
+ #movePad {
247
  position: relative;
248
+ width: 120px;
249
+ height: 120px;
250
+ background-color: rgba(255, 255, 255, 0.1);
251
  border-radius: 50%;
252
  }
253
 
254
+ #moveKnob {
255
  position: absolute;
256
+ width: 50px;
257
+ height: 50px;
258
+ background-color: rgba(255, 255, 255, 0.3);
259
  border-radius: 50%;
260
+ top: 35px;
261
+ left: 35px;
262
  }
263
 
264
+ @media (max-width: 768px) {
265
+ #mobileControls {
266
+ display: flex;
267
+ }
268
  }
269
  </style>
270
  </head>
271
  <body>
272
  <div id="gameContainer">
273
+ <canvas id="gameCanvas"></canvas>
274
+ <div id="crosshair"></div>
275
+ <div id="bloodEffect"></div>
276
+ <div id="enemyHitEffect"></div>
277
 
278
  <div id="uiContainer">
279
  <div id="healthBar">
280
  <div id="healthFill"></div>
281
  </div>
282
+ <div id="ammoCount">30/30</div>
283
+ <div id="scoreDisplay">SCORE: 0</div>
284
+ <div id="weaponDisplay">PISTOL</div>
285
+ <div id="reloadIndicator">
286
+ <div id="reloadFill"></div>
287
+ </div>
288
 
289
+ <div id="mobileControls">
290
+ <div id="movePad">
291
+ <div id="moveKnob"></div>
292
  </div>
293
+ <div id="shootBtn" class="mobile-btn">
294
  <i class="fas fa-fire"></i>
295
  </div>
296
  </div>
297
  </div>
298
 
299
  <div id="gameOverScreen">
300
+ <h1 class="text-5xl text-red-600 mb-8">GAME OVER</h1>
301
+ <p class="text-2xl mb-4">YOUR SCORE:</p>
302
+ <p class="text-4xl mb-12" id="finalScore">0</p>
303
+ <button id="restartBtn" class="btn">PLAY AGAIN</button>
304
  </div>
305
 
306
  <div id="startScreen">
307
+ <h1 class="text-6xl text-red-600 mb-8">2D FPS</h1>
308
+ <p class="text-xl mb-12">SURVIVE AS LONG AS YOU CAN</p>
309
+ <button id="startBtn" class="btn">START GAME</button>
310
+ <div class="mt-16 text-gray-400 text-center">
311
+ <p class="mb-4">CONTROLS:</p>
312
+ <p class="mb-2">WASD - MOVE</p>
313
+ <p class="mb-2">MOUSE - AIM</p>
314
+ <p class="mb-2">LEFT CLICK - SHOOT</p>
315
+ <p class="mb-2">R - RELOAD</p>
316
  </div>
317
  </div>
318
  </div>
319
 
320
  <script>
321
  // Game variables
322
+ const canvas = document.getElementById('gameCanvas');
323
+ const ctx = canvas.getContext('2d');
324
  const healthFill = document.getElementById('healthFill');
325
  const ammoCount = document.getElementById('ammoCount');
326
  const scoreDisplay = document.getElementById('scoreDisplay');
327
+ const weaponDisplay = document.getElementById('weaponDisplay');
328
  const gameOverScreen = document.getElementById('gameOverScreen');
329
  const finalScore = document.getElementById('finalScore');
330
  const startScreen = document.getElementById('startScreen');
331
  const startBtn = document.getElementById('startBtn');
332
  const restartBtn = document.getElementById('restartBtn');
333
+ const bloodEffect = document.getElementById('bloodEffect');
334
+ const reloadIndicator = document.getElementById('reloadIndicator');
335
+ const reloadFill = document.getElementById('reloadFill');
336
+ const enemyHitEffect = document.getElementById('enemyHitEffect');
337
  const shootBtn = document.getElementById('shootBtn');
338
+ const movePad = document.getElementById('movePad');
339
+ const moveKnob = document.getElementById('moveKnob');
340
 
341
+ // Game state
342
+ let gameWidth = window.innerWidth;
343
+ let gameHeight = window.innerHeight;
344
+ let playerX = 0;
345
+ let playerY = 0;
346
+ let playerAngle = 0;
347
+ let playerSpeed = 0.1;
348
  let health = 100;
 
 
349
  let score = 0;
350
  let gameRunning = false;
 
 
 
 
351
  let lastShotTime = 0;
 
 
352
  let lastEnemySpawn = 0;
353
+ let enemySpawnRate = 2000;
354
+ let isReloading = false;
355
+ let movePadActive = false;
356
+ let moveDirection = { x: 0, y: 0 };
357
 
358
+ // Weapon data
359
+ const weapons = {
360
+ pistol: {
361
+ name: "PISTOL",
362
+ damage: 25,
363
+ ammo: 30,
364
+ maxAmmo: 30,
365
+ reloadTime: 1000,
366
+ fireRate: 300,
367
+ color: "#aaa"
368
+ },
369
+ rifle: {
370
+ name: "RIFLE",
371
+ damage: 15,
372
+ ammo: 90,
373
+ maxAmmo: 30,
374
+ reloadTime: 1500,
375
+ fireRate: 100,
376
+ color: "#5a5"
377
+ },
378
+ shotgun: {
379
+ name: "SHOTGUN",
380
+ damage: 40,
381
+ ammo: 24,
382
+ maxAmmo: 8,
383
+ reloadTime: 2000,
384
+ fireRate: 800,
385
+ color: "#a55"
386
+ }
387
+ };
388
+
389
+ let currentWeapon = "pistol";
390
+ let enemies = [];
391
+ let walls = [];
392
+ let particles = [];
393
+
394
+ // Initialize canvas
395
+ canvas.width = gameWidth;
396
+ canvas.height = gameHeight;
397
 
398
  // Start screen
399
  startBtn.addEventListener('click', startGame);
 
401
  // Restart game
402
  restartBtn.addEventListener('click', startGame);
403
 
404
+ // Keyboard controls
405
+ const keys = {
406
+ w: false,
407
+ a: false,
408
+ s: false,
409
+ d: false
410
+ };
411
+
412
+ document.addEventListener('keydown', (e) => {
413
+ if (e.key.toLowerCase() === 'w') keys.w = true;
414
+ if (e.key.toLowerCase() === 'a') keys.a = true;
415
+ if (e.key.toLowerCase() === 's') keys.s = true;
416
+ if (e.key.toLowerCase() === 'd') keys.d = true;
417
+ if (e.key === 'r' && gameRunning && !isReloading) reload();
418
+ });
419
+
420
+ document.addEventListener('keyup', (e) => {
421
+ if (e.key.toLowerCase() === 'w') keys.w = false;
422
+ if (e.key.toLowerCase() === 'a') keys.a = false;
423
+ if (e.key.toLowerCase() === 's') keys.s = false;
424
+ if (e.key.toLowerCase() === 'd') keys.d = false;
425
+ });
426
+
427
+ // Mouse controls
428
+ document.addEventListener('mousemove', (e) => {
429
+ if (!gameRunning) return;
430
+
431
+ // Calculate angle based on mouse position
432
+ const centerX = gameWidth / 2;
433
+ const centerY = gameHeight / 2;
434
+ const mouseX = e.clientX;
435
+ const mouseY = e.clientY;
436
+
437
+ playerAngle = Math.atan2(mouseY - centerY, mouseX - centerX);
438
+ });
439
+
440
+ document.addEventListener('mousedown', (e) => {
441
+ if (e.button === 0 && gameRunning) { // Left click
442
+ shoot();
443
+ }
444
+ });
445
+
446
  // Touch controls for mobile
447
+ shootBtn.addEventListener('touchstart', (e) => {
448
+ e.preventDefault();
449
+ if (gameRunning) shoot();
450
+ });
451
 
452
+ movePad.addEventListener('touchstart', handleMoveStart);
453
+ document.addEventListener('touchmove', handleMoveMove);
454
+ document.addEventListener('touchend', handleMoveEnd);
455
+
456
+ function handleMoveStart(e) {
457
+ e.preventDefault();
458
+ movePadActive = true;
459
+ handleMoveMove(e);
460
+ }
461
 
462
+ function handleMoveMove(e) {
463
+ if (!movePadActive) return;
464
+ e.preventDefault();
465
+
466
+ const padRect = movePad.getBoundingClientRect();
467
+ const padCenterX = padRect.left + padRect.width / 2;
468
+ const padCenterY = padRect.top + padRect.height / 2;
469
+
470
+ let touchX, touchY;
471
+ if (e.touches) {
472
+ touchX = e.touches[0].clientX;
473
+ touchY = e.touches[0].clientY;
474
+ } else {
475
+ touchX = e.clientX;
476
+ touchY = e.clientY;
477
+ }
478
+
479
+ const dx = touchX - padCenterX;
480
+ const dy = touchY - padCenterY;
481
+ const distance = Math.min(50, Math.sqrt(dx * dx + dy * dy));
482
+ const angle = Math.atan2(dy, dx);
483
+
484
+ // Calculate direction vector
485
+ moveDirection = {
486
+ x: Math.cos(angle) * (distance / 50),
487
+ y: Math.sin(angle) * (distance / 50)
488
+ };
489
+
490
+ // Move knob
491
+ const knobX = Math.cos(angle) * distance;
492
+ const knobY = Math.sin(angle) * distance;
493
+
494
+ moveKnob.style.transform = `translate(${knobX}px, ${knobY}px)`;
495
+ }
496
+
497
+ function handleMoveEnd(e) {
498
+ e.preventDefault();
499
+ movePadActive = false;
500
+ moveDirection = { x: 0, y: 0 };
501
+ moveKnob.style.transform = 'translate(0, 0)';
502
+ }
503
 
504
  function startGame() {
505
  // Reset game state
506
  health = 100;
 
507
  score = 0;
508
+ playerX = 0;
509
+ playerY = 0;
510
+ playerAngle = 0;
511
  enemies = [];
512
+ particles = [];
513
+ walls = [];
514
+
515
+ // Reset weapons
516
+ weapons.pistol.ammo = weapons.pistol.maxAmmo;
517
+ weapons.rifle.ammo = weapons.rifle.maxAmmo;
518
+ weapons.shotgun.ammo = weapons.shotgun.maxAmmo;
519
+ currentWeapon = "pistol";
520
 
521
  // Update UI
522
  updateHealth();
523
  updateAmmo();
524
  updateScore();
525
+ updateWeapon();
 
 
526
 
527
  // Hide screens
528
  gameOverScreen.style.display = 'none';
529
  startScreen.style.display = 'none';
530
 
531
+ // Generate walls
532
+ generateWalls();
 
 
 
533
 
534
  // Start game loop
535
  gameRunning = true;
 
542
 
543
  const now = Date.now();
544
 
545
+ // Clear canvas
546
+ ctx.clearRect(0, 0, gameWidth, gameHeight);
547
+
548
+ // Draw floor and ceiling
549
+ ctx.fillStyle = '#333';
550
+ ctx.fillRect(0, 0, gameWidth, gameHeight / 2);
551
+ ctx.fillStyle = '#555';
552
+ ctx.fillRect(0, gameHeight / 2, gameWidth, gameHeight / 2);
553
+
554
+ // Draw walls
555
+ drawWalls();
556
+
557
+ // Move player
558
+ let moveX = 0;
559
+ let moveY = 0;
560
+
561
+ if (keys.w || moveDirection.y < -0.5) moveY -= playerSpeed;
562
+ if (keys.s || moveDirection.y > 0.5) moveY += playerSpeed;
563
+ if (keys.a || moveDirection.x < -0.5) moveX -= playerSpeed;
564
+ if (keys.d || moveDirection.x > 0.5) moveX += playerSpeed;
565
+
566
+ // Normalize diagonal movement
567
+ if (moveX !== 0 && moveY !== 0) {
568
+ moveX *= 0.7071; // 1/sqrt(2)
569
+ moveY *= 0.7071;
570
+ }
571
+
572
+ // Check wall collisions
573
+ const newX = playerX + moveX * Math.cos(playerAngle) - moveY * Math.sin(playerAngle);
574
+ const newY = playerY + moveX * Math.sin(playerAngle) + moveY * Math.cos(playerAngle);
575
+
576
+ if (!checkWallCollision(newX, newY)) {
577
+ playerX = newX;
578
+ playerY = newY;
579
+ }
580
+
581
  // Spawn enemies
582
  if (now - lastEnemySpawn > enemySpawnRate) {
583
  spawnEnemy();
 
589
  }
590
  }
591
 
592
+ // Update and draw enemies
593
+ updateEnemies();
594
+
595
+ // Update and draw particles
596
+ updateParticles();
597
+
598
+ // Draw weapon
599
+ drawWeapon();
600
+
601
+ // Check game over
602
+ if (health <= 0) {
603
+ gameOver();
604
+ return;
605
+ }
606
+
607
+ // Continue game loop
608
+ requestAnimationFrame(gameLoop);
609
+ }
610
+
611
+ function generateWalls() {
612
+ // Create a simple maze-like structure
613
+ for (let x = -10; x <= 10; x++) {
614
+ for (let y = -10; y <= 10; y++) {
615
+ // Border walls
616
+ if (x === -10 || x === 10 || y === -10 || y === 10) {
617
+ walls.push({ x, y });
618
+ }
619
+ // Random inner walls
620
+ else if (Math.abs(x) > 2 || Math.abs(y) > 2) {
621
+ if (Math.random() < 0.2) {
622
+ walls.push({ x, y });
623
+ }
624
+ }
625
+ }
626
+ }
627
+ }
628
+
629
+ function drawWalls() {
630
+ const fov = Math.PI / 3; // 60 degrees
631
+ const halfFov = fov / 2;
632
+ const numRays = gameWidth;
633
+ const rayAngleStep = fov / numRays;
634
+
635
+ for (let i = 0; i < numRays; i++) {
636
+ const rayAngle = playerAngle - halfFov + i * rayAngleStep;
637
 
638
+ // Cast ray
639
+ let rayX = playerX;
640
+ let rayY = playerY;
641
+ let rayDist = 0;
642
+ let hitWall = false;
643
+ let wallType = 0;
644
 
645
+ // Ray casting loop
646
+ while (!hitWall && rayDist < 20) {
647
+ rayDist += 0.05;
648
+ rayX = playerX + Math.cos(rayAngle) * rayDist;
649
+ rayY = playerY + Math.sin(rayAngle) * rayDist;
650
+
651
+ // Check if ray hit a wall
652
+ const mapX = Math.floor(rayX + 0.5);
653
+ const mapY = Math.floor(rayY + 0.5);
654
+
655
+ if (walls.some(wall => wall.x === mapX && wall.y === mapY)) {
656
+ hitWall = true;
657
+ wallType = (mapX + mapY) % 2;
658
+ }
659
+ }
660
+
661
+ // Fix fisheye effect
662
+ const correctedDist = rayDist * Math.cos(rayAngle - playerAngle);
663
+
664
+ // Calculate wall height
665
+ const wallHeight = Math.min(gameHeight, gameHeight / correctedDist * 2);
666
+ const wallTop = (gameHeight - wallHeight) / 2;
667
+
668
+ // Draw wall slice
669
+ const wallColor = wallType === 0 ? '#600' : '#333';
670
+ ctx.fillStyle = wallColor;
671
+ ctx.fillRect(i, wallTop, 1, wallHeight);
672
+
673
+ // Add shading based on distance
674
+ const shade = Math.min(1, correctedDist / 10);
675
+ ctx.fillStyle = `rgba(0, 0, 0, ${shade})`;
676
+ ctx.fillRect(i, wallTop, 1, wallHeight);
677
+ }
678
+ }
679
+
680
+ function spawnEnemy() {
681
+ // Find a position not too close to player
682
+ let angle = Math.random() * Math.PI * 2;
683
+ let distance = 5 + Math.random() * 5;
684
+ let x = playerX + Math.cos(angle) * distance;
685
+ let y = playerY + Math.sin(angle) * distance;
686
+
687
+ // Make sure it's not inside a wall
688
+ while (checkWallCollision(x, y)) {
689
+ angle = Math.random() * Math.PI * 2;
690
+ distance = 5 + Math.random() * 5;
691
+ x = playerX + Math.cos(angle) * distance;
692
+ y = playerY + Math.sin(angle) * distance;
693
  }
694
 
695
+ enemies.push({
696
+ x,
697
+ y,
698
+ health: 100,
699
+ speed: 0.03 + Math.random() * 0.02,
700
+ lastAttack: 0,
701
+ attackCooldown: 1000,
702
+ damage: 10
703
+ });
704
+ }
705
+
706
+ function updateEnemies() {
707
+ for (let i = enemies.length - 1; i >= 0; i--) {
708
+ const enemy = enemies[i];
709
 
710
+ // Move toward player
711
+ const angleToPlayer = Math.atan2(playerY - enemy.y, playerX - enemy.x);
712
+ const moveX = Math.cos(angleToPlayer) * enemy.speed;
713
+ const moveY = Math.sin(angleToPlayer) * enemy.speed;
714
+
715
+ // Check wall collisions
716
+ if (!checkWallCollision(enemy.x + moveX, enemy.y + moveY)) {
717
+ enemy.x += moveX;
718
+ enemy.y += moveY;
719
  }
720
 
721
+ // Check distance to player
722
+ const dx = playerX - enemy.x;
723
+ const dy = playerY - enemy.y;
724
+ const distance = Math.sqrt(dx * dx + dy * dy);
725
 
726
+ // Attack if close enough
727
+ const now = Date.now();
728
+ if (distance < 1 && now - enemy.lastAttack > enemy.attackCooldown) {
729
+ takeDamage(enemy.damage);
730
+ enemy.lastAttack = now;
731
+
732
+ // Blood effect
733
+ bloodEffect.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
734
+ setTimeout(() => {
735
+ bloodEffect.style.backgroundColor = 'rgba(255, 0, 0, 0)';
736
+ }, 200);
737
  }
 
 
 
 
 
 
738
 
739
+ // Draw enemy
740
+ const enemyAngle = angleToPlayer - playerAngle;
741
+ const enemyDistance = distance;
742
 
743
+ // Only draw if in field of view
744
+ if (Math.abs(enemyAngle) < Math.PI / 3) {
745
+ const correctedDist = enemyDistance * Math.cos(enemyAngle);
746
+ const enemySize = Math.min(200, gameHeight / correctedDist);
747
+ const enemyX = gameWidth / 2 + Math.tan(enemyAngle) * gameWidth / 2;
748
+ const enemyY = gameHeight / 2;
749
+
750
+ // Simple enemy sprite
751
+ ctx.fillStyle = '#f00';
752
+ ctx.beginPath();
753
+ ctx.arc(enemyX, enemyY, enemySize / 2, 0, Math.PI * 2);
754
+ ctx.fill();
755
+
756
+ // Health bar
757
+ const healthBarWidth = enemySize;
758
+ const healthBarHeight = 5;
759
+ ctx.fillStyle = '#300';
760
+ ctx.fillRect(enemyX - healthBarWidth / 2, enemyY - enemySize / 2 - 10, healthBarWidth, healthBarHeight);
761
+ ctx.fillStyle = '#f00';
762
+ ctx.fillRect(enemyX - healthBarWidth / 2, enemyY - enemySize / 2 - 10, healthBarWidth * (enemy.health / 100), healthBarHeight);
763
  }
764
 
765
+ // Remove dead enemies
766
+ if (enemy.health <= 0) {
767
+ enemies.splice(i, 1);
768
+
769
+ // Add blood particles
770
+ for (let j = 0; j < 10; j++) {
771
+ particles.push({
772
+ x: enemy.x,
773
+ y: enemy.y,
774
+ size: 0.1 + Math.random() * 0.1,
775
+ color: '#f00',
776
+ speed: 0.05 + Math.random() * 0.1,
777
+ angle: Math.random() * Math.PI * 2,
778
+ life: 30 + Math.random() * 30
779
+ });
 
 
 
 
 
 
 
780
  }
 
 
 
 
 
 
 
 
 
781
 
782
+ // Increase score
783
+ score += 10;
784
+ updateScore();
 
 
 
 
 
 
 
 
785
 
786
+ // Random weapon drop
787
+ if (Math.random() < 0.2) {
788
+ const weaponTypes = ['pistol', 'rifle', 'shotgun'];
789
+ const randomWeapon = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
790
+
791
+ if (randomWeapon !== currentWeapon) {
792
+ weapons[randomWeapon].ammo = weapons[randomWeapon].maxAmmo;
793
+ currentWeapon = randomWeapon;
794
+ updateWeapon();
795
+
796
+ // Show weapon pickup effect
797
+ enemyHitEffect.style.backgroundColor = 'rgba(0, 255, 0, 0.3)';
798
+ setTimeout(() => {
799
+ enemyHitEffect.style.backgroundColor = 'rgba(255, 255, 255, 0)';
800
+ }, 200);
801
+ }
802
+ }
803
  }
804
+ }
 
 
 
805
  }
806
 
807
+ function updateParticles() {
808
+ for (let i = particles.length - 1; i >= 0; i--) {
809
+ const p = particles[i];
810
+
811
+ // Update position
812
+ p.x += Math.cos(p.angle) * p.speed;
813
+ p.y += Math.sin(p.angle) * p.speed;
814
+ p.life--;
815
+
816
+ // Draw particle
817
+ const angle = Math.atan2(p.y - playerY, p.x - playerX) - playerAngle;
818
+ const distance = Math.sqrt(Math.pow(p.x - playerX, 2) + Math.pow(p.y - playerY, 2));
819
+
820
+ if (Math.abs(angle) < Math.PI / 3) {
821
+ const correctedDist = distance * Math.cos(angle);
822
+ const size = Math.min(20, p.size * gameHeight / correctedDist);
823
+ const x = gameWidth / 2 + Math.tan(angle) * gameWidth / 2;
824
+ const y = gameHeight / 2;
825
+
826
+ ctx.fillStyle = p.color;
827
+ ctx.beginPath();
828
+ ctx.arc(x, y, size, 0, Math.PI * 2);
829
+ ctx.fill();
830
+ }
831
+
832
+ // Remove dead particles
833
+ if (p.life <= 0) {
834
+ particles.splice(i, 1);
835
+ }
836
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
837
  }
838
 
839
+ function drawWeapon() {
840
+ const weapon = weapons[currentWeapon];
841
+ const weaponHeight = gameHeight / 2;
842
+ const weaponWidth = weaponHeight * 0.5;
843
+ const weaponX = gameWidth / 2 - weaponWidth / 2;
844
+ const weaponY = gameHeight - weaponHeight;
845
 
846
+ // Simple weapon graphic
847
+ ctx.fillStyle = weapon.color;
848
+ ctx.fillRect(weaponX, weaponY, weaponWidth, weaponHeight);
 
 
 
 
 
 
 
849
 
850
+ // Add some details
851
+ ctx.fillStyle = '#333';
852
+ ctx.fillRect(weaponX + 10, weaponY + 20, weaponWidth - 20, 10);
853
+
854
+ // Muzzle flash when shooting
855
+ const now = Date.now();
856
+ if (now - lastShotTime < 100) {
857
+ ctx.fillStyle = '#ff0';
858
+ ctx.fillRect(weaponX + weaponWidth, weaponY + 20, 30, 10);
859
+ }
860
  }
861
 
862
  function shoot() {
863
  const now = Date.now();
864
+ const weapon = weapons[currentWeapon];
865
+
866
+ if (now - lastShotTime < weapon.fireRate || isReloading) return;
867
+ if (weapon.ammo <= 0) {
868
+ reload();
869
+ return;
870
+ }
871
 
872
  lastShotTime = now;
873
+ weapon.ammo--;
874
  updateAmmo();
875
 
876
+ // Create muzzle flash particle
877
+ particles.push({
878
+ x: playerX + Math.cos(playerAngle) * 0.5,
879
+ y: playerY + Math.sin(playerAngle) * 0.5,
880
+ size: 0.2,
881
+ color: '#ff0',
882
+ speed: 0.2,
883
+ angle: playerAngle,
884
+ life: 5
885
+ });
886
 
887
+ // Check if hit an enemy
888
+ for (let i = 0; i < enemies.length; i++) {
889
+ const enemy = enemies[i];
890
+
891
+ // Calculate angle to enemy
892
+ const angleToEnemy = Math.atan2(enemy.y - playerY, enemy.x - playerX);
893
+ const angleDiff = Math.abs(normalizeAngle(angleToEnemy - playerAngle));
894
+
895
+ // Check if enemy is in front of player (within 5 degrees)
896
+ if (angleDiff < 0.087) { // ~5 degrees in radians
897
+ const distance = Math.sqrt(Math.pow(enemy.x - playerX, 2) + Math.pow(enemy.y - playerY, 2));
898
+
899
+ // Check line of sight (simple version)
900
+ let blocked = false;
901
+ const steps = 10;
902
+ for (let j = 1; j <= steps; j++) {
903
+ const checkX = playerX + (enemy.x - playerX) * (j / steps);
904
+ const checkY = playerY + (enemy.y - playerY) * (j / steps);
905
+
906
+ if (checkWallCollision(checkX, checkY)) {
907
+ blocked = true;
908
+ break;
909
+ }
910
+ }
911
+
912
+ if (!blocked) {
913
+ // Hit the enemy
914
+ enemy.health -= weapon.damage;
915
+
916
+ // Hit effect
917
+ enemyHitEffect.style.backgroundColor = 'rgba(255, 255, 255, 0.5)';
918
+ setTimeout(() => {
919
+ enemyHitEffect.style.backgroundColor = 'rgba(255, 255, 255, 0)';
920
+ }, 100);
921
+
922
+ // Blood particles
923
+ for (let j = 0; j < 5; j++) {
924
+ particles.push({
925
+ x: enemy.x,
926
+ y: enemy.y,
927
+ size: 0.1 + Math.random() * 0.1,
928
+ color: '#f00',
929
+ speed: 0.05 + Math.random() * 0.1,
930
+ angle: playerAngle + (Math.random() - 0.5) * 0.5,
931
+ life: 20 + Math.random() * 20
932
+ });
933
+ }
934
+
935
+ break; // Only hit one enemy per shot
936
+ }
937
+ }
938
+ }
939
 
940
+ // Auto reload if empty
941
+ if (weapon.ammo <= 0) {
942
+ reload();
943
+ }
944
+ }
945
+
946
+ function reload() {
947
+ if (isReloading || weapons[currentWeapon].ammo === weapons[currentWeapon].maxAmmo) return;
948
 
949
+ isReloading = true;
950
+ reloadIndicator.style.display = 'block';
951
+ reloadFill.style.width = '0%';
952
 
953
+ const reloadTime = weapons[currentWeapon].reloadTime;
954
+ const startTime = Date.now();
955
 
956
+ const reloadInterval = setInterval(() => {
957
+ const elapsed = Date.now() - startTime;
958
+ const progress = (elapsed / reloadTime) * 100;
959
+
960
+ reloadFill.style.width = `${progress}%`;
961
+
962
+ if (elapsed >= reloadTime) {
963
+ clearInterval(reloadInterval);
964
+ weapons[currentWeapon].ammo = weapons[currentWeapon].maxAmmo;
965
  updateAmmo();
966
+ isReloading = false;
967
+ reloadIndicator.style.display = 'none';
968
+ }
969
+ }, 16);
970
  }
971
 
972
  function takeDamage(amount) {
973
  health -= amount;
974
  updateHealth();
975
 
 
 
 
 
 
 
 
976
  if (health <= 0) {
977
  health = 0;
978
  updateHealth();
 
981
  }
982
 
983
  function updateHealth() {
984
+ healthFill.style.width = `${health}%`;
985
 
986
  // Change color based on health
987
+ if (health > 60) {
988
+ healthFill.style.backgroundColor = '#0f0';
989
+ } else if (health > 30) {
990
+ healthFill.style.backgroundColor = '#ff0';
991
  } else {
992
+ healthFill.style.backgroundColor = '#f00';
993
  }
994
  }
995
 
996
  function updateAmmo() {
997
+ ammoCount.textContent = `${weapons[currentWeapon].ammo}/${weapons[currentWeapon].maxAmmo}`;
998
  }
999
 
1000
  function updateScore() {
1001
+ scoreDisplay.textContent = `SCORE: ${score}`;
1002
+ }
1003
+
1004
+ function updateWeapon() {
1005
+ weaponDisplay.textContent = weapons[currentWeapon].name;
1006
  }
1007
 
1008
  function gameOver() {
 
1011
  gameOverScreen.style.display = 'flex';
1012
  }
1013
 
1014
+ function checkWallCollision(x, y) {
1015
+ const mapX = Math.floor(x + 0.5);
1016
+ const mapY = Math.floor(y + 0.5);
1017
 
1018
+ return walls.some(wall => wall.x === mapX && wall.y === mapY);
 
 
 
 
 
1019
  }
1020
 
1021
+ function normalizeAngle(angle) {
1022
+ while (angle < -Math.PI) angle += Math.PI * 2;
1023
+ while (angle > Math.PI) angle -= Math.PI * 2;
1024
+ return angle;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
  }
1026
 
1027
  // Handle window resize
1028
  window.addEventListener('resize', () => {
1029
+ gameWidth = window.innerWidth;
1030
+ gameHeight = window.innerHeight;
1031
+ canvas.width = gameWidth;
1032
+ canvas.height = gameHeight;
1033
  });
1034
  </script>
1035
  <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=Davi111/games" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
prompts.txt CHANGED
@@ -1,2 +1,3 @@
1
  Criar o free fire lite
2
- Crie free fire 2d
 
 
1
  Criar o free fire lite
2
+ Crie free fire 2d
3
+ Crie um jogo fps