Dragoy commited on
Commit
e0ebe8e
·
verified ·
1 Parent(s): 503f471

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +1099 -19
  3. prompts.txt +5 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Tank Battle Royale One Shot
3
- emoji: 🏢
4
- colorFrom: blue
5
- colorTo: blue
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: tank-battle-royale-one-shot
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: yellow
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,1099 @@
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>Tank Battle Royale - One Shot Eliminations</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
9
+ <style>
10
+ body {
11
+ overflow: hidden;
12
+ touch-action: none;
13
+ background: linear-gradient(135deg, #1a1f38, #0d1124);
14
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
15
+ }
16
+ #gameContainer {
17
+ border: 3px solid #2c3e50;
18
+ border-radius: 8px;
19
+ box-shadow: 0 0 30px rgba(0, 0, 0, 0.6);
20
+ }
21
+ .tank {
22
+ position: absolute;
23
+ transition: transform 0.1s;
24
+ z-index: 10;
25
+ }
26
+ .health-bar {
27
+ width: 60px;
28
+ height:-5px;
29
+ background-color: #ff6b6b;
30
+ position: absolute;
31
+ top: -15px;
32
+ left: -10px;
33
+ border-radius: 3px;
34
+ z-index: 11;
35
+ }
36
+ .health-fill {
37
+ height: 100%;
38
+ background-color: #51cf66;
39
+ border-radius: 3px;
40
+ transition: width 0.3s;
41
+ }
42
+ .bullet {
43
+ position: absolute;
44
+ border-radius: 50%;
45
+ z-index: 9;
46
+ }
47
+ .explosion {
48
+ position: absolute;
49
+ pointer-events: none;
50
+ z-index: 100;
51
+ }
52
+ .control-btn {
53
+ width: 70px;
54
+ height: 70px;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ border-radius: 50%;
59
+ opacity: 0.8;
60
+ transition: all 0.1s;
61
+ user-select: none;
62
+ }
63
+ .control-btn:active, .active {
64
+ transform: scale(0.9);
65
+ opacity: 1;
66
+ }
67
+ .tank-body {
68
+ width: 40px;
69
+ height: 40px;
70
+ border-radius: 4px;
71
+ position: relative;
72
+ }
73
+ .tank-turret {
74
+ position: absolute;
75
+ width: 25px;
76
+ height: 8px;
77
+ border-radius: 3px;
78
+ top: 16px;
79
+ left: 40px;
80
+ }
81
+ .grid-line {
82
+ position: absolute;
83
+ background-color: rgba(255, 255, 255, 0.05);
84
+ }
85
+ #instructions {
86
+ background: rgba(0, 0, 0, 0.7);
87
+ backdrop-filter: blur(10px);
88
+ border-radius: 12px;
89
+ }
90
+ .power-up {
91
+ position: absolute;
92
+ z-index: 8;
93
+ animation: float 3s ease-in-out infinite;
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ }
98
+ @keyframes float {
99
+ 0% { transform: translateY(0px); }
100
+ 50% { transform: translateY(-10px); }
101
+ 100% { transform: translateY(0px); }
102
+ }
103
+ .flashing {
104
+ animation: flash 0.5s infinite;
105
+ }
106
+ @keyframes flash {
107
+ 0%, 100% { opacity: 1; }
108
+ 50% { opacity: 0.3; }
109
+ }
110
+ .damage-indicator {
111
+ position: absolute;
112
+ color: #ff6b6b;
113
+ font-weight: bold;
114
+ z-index: 100;
115
+ pointer-events: none;
116
+ animation: floatUp 1s ease-out forwards;
117
+ }
118
+ @keyframes floatUp {
119
+ 0% { transform: translateY(0); opacity: 1; }
120
+ 100% { transform: translateY(-50px); opacity: 0; }
121
+ }
122
+ .hit-effect {
123
+ position: absolute;
124
+ pointer-events: none;
125
+ opacity: 0;
126
+ transition: opacity 0.3s;
127
+ }
128
+ </style>
129
+ </head>
130
+ <body class="min-h-screen flex items-center justify-center p-4">
131
+ <div class="w-full max-w-3xl">
132
+ <h1 class="text-4xl font-bold text-center mb-2 bg-clip-text text-transparent bg-gradient-to-r from-yellow-400 to-red-500">
133
+ <i class="fas fa-tank mr-3"></i>TANK BATTLE ROYALE
134
+ <span class="text-sm ml-2 bg-red-600 text-white rounded-full px-2 py-1">ONE-SHOT ELIMINATIONS</span>
135
+ </h1>
136
+
137
+ <div class="flex flex-col md:flex-row justify-between items-center mb-4">
138
+ <div class="flex flex-wrap gap-2">
139
+ <div class="bg-gray-800 px-4 py-2 rounded-lg shadow-lg border border-gray-700 flex items-center">
140
+ <i class="fas fa-heart text-red-500 text-lg mr-2"></i>
141
+ <span class="font-bold text-white">HEALTH:
142
+ <span id="health" class="text-green-300 ml-1">100</span>%
143
+ </span>
144
+ </div>
145
+ <div class="bg-gray-800 px-4 py-2 rounded-lg shadow-lg border border-gray-700 flex items-center">
146
+ <i class="fas fa-trophy text-yellow-400 text-lg mr-2"></i>
147
+ <span class="font-bold text-white">SCORE:
148
+ <span id="score" class="text-yellow-300 ml-1">0</span>
149
+ </span>
150
+ </div>
151
+ <div class="bg-gray-800 px-4 py-2 rounded-lg shadow-lg border border-gray-700 flex items-center">
152
+ <i class="fas fa-skull text-red-500 text-lg mr-2"></i>
153
+ <span class="font-bold text-white">ENEMIES:
154
+ <span id="enemies" class="text-red-300 ml-1">0</span>
155
+ </span>
156
+ </div>
157
+ <div class="bg-gray-800 px-4 py-2 rounded-lg shadow-lg border border-gray-700 flex items-center">
158
+ <i class="fas fa-bolt text-purple-500 text-lg mr-2"></i>
159
+ <span class="font-bold text-white">FIREPOWER:
160
+ <span id="firepower" class="text-purple-300 ml-1">INSTANT</span>
161
+ </span>
162
+ </div>
163
+ </div>
164
+
165
+ <div class="mt-4 md:mt-0">
166
+ <button id="pauseBtn" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition">
167
+ <i class="fas fa-pause mr-2"></i>Pause
168
+ </button>
169
+ </div>
170
+ </div>
171
+
172
+ <div class="relative" id="gameWrapper">
173
+ <canvas id="gameCanvas" width="800" height="500" class="w-full bg-gradient-to-b from-gray-900 to-gray-800 rounded-lg shadow-xl"></canvas>
174
+
175
+ <div class="absolute top-2 left-2 bg-green-900/80 p-2 rounded text-green-200 font-bold border border-green-600">
176
+ <i class="fas fa-star mr-1"></i> ONE-SHOT ELIMINATION MODE
177
+ </div>
178
+
179
+ <!-- Game Over Screen -->
180
+ <div id="gameOver" class="absolute inset-0 bg-gradient-to-br from-red-900/90 to-black/90 flex flex-col items-center justify-center rounded-lg text-center hidden">
181
+ <h2 class="text-5xl font-bold text-red-400 mb-2">MISSION FAILED</h2>
182
+ <p class="text-2xl text-white mb-4">Your tank has been destroyed!</p>
183
+ <p class="text-xl text-yellow-300 mb-4">Final Score: <span id="finalScore">0</span></p>
184
+ <button id="restartBtn" class="mt-6 bg-gradient-to-r from-yellow-500 to-red-500 hover:from-yellow-600 hover:to-red-600 text-xl font-bold text-white py-3 px-8 rounded-full transition transform hover:scale-105">
185
+ <i class="fas fa-redo mr-3"></i>Play Again
186
+ </button>
187
+ </div>
188
+
189
+ <!-- Start Screen -->
190
+ <div id="startScreen" class="absolute inset-0 bg-gradient-to-br from-blue-900/90 to-black/90 flex flex-col items-center justify-center rounded-lg text-center">
191
+ <div id="instructions" class="p-8 max-w-3xl">
192
+ <h2 class="text-4xl font-bold mb-6 bg-clip-text text-transparent bg-gradient-to-r from-green-400 to-blue-500">TANK COMBAT GUIDE</h2>
193
+
194
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
195
+ <div class="bg-gray-800/80 p-4 rounded-xl">
196
+ <div class="text-4xl text-yellow-400 mb-4"><i class="fas fa-laptop"></i></div>
197
+ <h3 class="text-xl font-bold text-white mb-2">ONE-SHOT MODE</h3>
198
+ <ul class="text-gray-300 text-left">
199
+ <li><i class="fas fa-bolt text-green-400"></i> Your shots destroy enemies instantly!</li>
200
+ <li><i class="fas fa-heart text-red-400"></i> Enemies still require multiple hits to destroy you</li>
201
+ <li><i class="fas fa-crown text-yellow-300"></i> Earn extra points for consecutive kills</li>
202
+ </ul>
203
+ </div>
204
+
205
+ <div class="bg-gray-800/80 p-4 rounded-xl">
206
+ <div class="text-4xl text-blue-400 mb-4"><i class="fas fa-keyboard"></i></div>
207
+ <h3 class="text-xl font-bold text-white mb-2">Controls</h3>
208
+ <ul class="text-gray-300 text-left">
209
+ <li><i class="fas fa-arrow-up text-green-400"></i> Move Forward</li>
210
+ <li><i class="fas fa-arrow-down text-green-400"></i> Move Backward</li>
211
+ <li><i class="fas fa-arrow-left text-green-400"></i> Rotate Left</li>
212
+ <li><i class="fas fa-arrow-right text-green-400"></i> Rotate Right</li>
213
+ <li><i class="fas fa-space-shuttle text-red-400"></i> Fire Weapon</li>
214
+ </ul>
215
+ </div>
216
+ </div>
217
+
218
+ <button id="startBtn" class="mt-4 bg-gradient-to-r from-green-500 to-blue-600 hover:from-green-600 hover:to-blue-700 text-2xl font-bold text-white py-4 px-12 rounded-full transition transform hover:scale-105">
219
+ <i class="fas fa-tank mr-3 animate-pulse"></i>DEPLOY TO BATTLEFIELD
220
+ </button>
221
+ </div>
222
+ </div>
223
+ </div>
224
+
225
+ <!-- Mobile Controls -->
226
+ <div id="mobileControls" class="mt-6 grid grid-cols-3 gap-4 select-none hidden">
227
+ <div></div> <!-- Empty spacer -->
228
+ <div class="flex justify-center">
229
+ <div class="control-btn bg-yellow-500" id="mobileUp">
230
+ <i class="fas fa-arrow-up text-3xl text-white"></i>
231
+ </div>
232
+ </div>
233
+ <div></div> <!-- Empty spacer -->
234
+
235
+ <div class="flex justify-center">
236
+ <div class="control-btn bg-yellow-500" id="mobileLeft">
237
+ <i class="fas fa-arrow-left text-3xl text-white"></i>
238
+ </div>
239
+ </div>
240
+ <div class="flex justify-center">
241
+ <div class="control-btn bg-red-600" id="mobileShoot">
242
+ <i class="fas fa-fire text-3xl text-white"></i>
243
+ </div>
244
+ </div>
245
+ <div class="flex justify-center">
246
+ <div class="control-btn bg-yellow-500" id="mobileRight">
247
+ <i class="fas fa-arrow-right text-3xl text-white"></i>
248
+ </div>
249
+ </div>
250
+
251
+ <div></div> <!-- Empty spacer -->
252
+ <div class="flex justify-center">
253
+ <div class="control-btn bg-yellow-500" id="mobileDown">
254
+ <i class="fas fa-arrow-down text-3xl text-white"></i>
255
+ </div>
256
+ </div>
257
+ <div></div> <!-- Empty spacer -->
258
+ </div>
259
+
260
+ <div class="mt-6 flex justify-center">
261
+ <div class="bg-gray-800/80 p-4 rounded-xl border border-gray-700 shadow-lg">
262
+ <p class="text-white text-center"><i class="fas fa-lightbulb text-yellow-300 mr-2"></i>Destroy enemies with a single shot! But beware - enemies still require multiple hits.</p>
263
+ </div>
264
+ </div>
265
+ </div>
266
+
267
+ <script>
268
+ // Game variables
269
+ const canvas = document.getElementById('gameCanvas');
270
+ const ctx = canvas.getContext('2d');
271
+ const healthDisplay = document.getElementById('health');
272
+ const scoreDisplay = document.getElementById('score');
273
+ const enemiesDisplay = document.getElementById('enemies');
274
+ const firepowerDisplay = document.getElementById('firepower');
275
+ const startBtn = document.getElementById('startBtn');
276
+ const startScreen = document.getElementById('startScreen');
277
+ const gameOverScreen = document.getElementById('gameOver');
278
+ const restartBtn = document.getElementById('restartBtn');
279
+ const pauseBtn = document.getElementById('pauseBtn');
280
+ const finalScore = document.getElementById('finalScore');
281
+ const mobileControls = document.getElementById('mobileControls');
282
+
283
+ // Initialize control buttons
284
+ const mobileUp = document.getElementById('mobileUp');
285
+ const mobileDown = document.getElementById('mobileDown');
286
+ const mobileLeft = document.getElementById('mobileLeft');
287
+ const mobileRight = document.getElementById('mobileRight');
288
+ const mobileShoot = document.getElementById('mobileShoot');
289
+
290
+ // Game state
291
+ let gameRunning = false;
292
+ let isPaused = false;
293
+ let score = 0;
294
+ let player;
295
+ let enemies = [];
296
+ let bullets = [];
297
+ let explosions = [];
298
+ let particles = [];
299
+ let gridLines = [];
300
+ let keys = {};
301
+ let lastShotTime = 0;
302
+ let enemySpawnTimer = 0;
303
+ let gameTime = 0;
304
+ let comboCounter = 0;
305
+ let comboTimeout = null;
306
+ let obstacleMap = [];
307
+
308
+ // Tank colors
309
+ const tankColors = {
310
+ player: '#3498db',
311
+ enemy: '#e74c3c'
312
+ };
313
+
314
+ // Map and obstacles
315
+ function generateObstacleMap() {
316
+ const width = canvas.width;
317
+ const height = canvas.height;
318
+
319
+ // Initialize obstacle map (0 = empty, 1 = obstacle)
320
+ obstacleMap = Array(Math.floor(height/20)).fill().map(() => Array(Math.floor(width/20)).fill(0));
321
+
322
+ // Add border obstacles
323
+ for(let i = 0; i < obstacleMap[0].length; i++) {
324
+ obstacleMap[0][i] = 1;
325
+ obstacleMap[obstacleMap.length-1][i] = 1;
326
+ }
327
+ for(let i = 0; i < obstacleMap.length; i++) {
328
+ obstacleMap[i][0] = 1;
329
+ obstacleMap[i][obstacleMap[0].length-1] = 1;
330
+ }
331
+
332
+ // Add some random obstacles
333
+ for(let i = 0; i < 20; i++) {
334
+ const row = Math.floor(Math.random() * (obstacleMap.length - 4)) + 2;
335
+ const col = Math.floor(Math.random() * (obstacleMap[0].length - 4)) + 2;
336
+ obstacleMap[row][col] = 1;
337
+
338
+ // Make the obstacles larger than single cells
339
+ if(row+1 < obstacleMap.length) obstacleMap[row+1][col] = 1;
340
+ if(col+1 < obstacleMap[0].length) obstacleMap[row][col+1] = 1;
341
+ }
342
+ }
343
+
344
+ // Draw obstacles
345
+ function drawObstacles() {
346
+ obstacleMap.forEach((row, i) => {
347
+ row.forEach((cell, j) => {
348
+ if(cell === 1) {
349
+ ctx.fillStyle = '#34495e';
350
+ ctx.fillRect(j*20, i*20, 20, 20);
351
+ ctx.fillStyle = '#2c3e50';
352
+ ctx.fillRect(j*20+4, i*20+4, 12, 12);
353
+ }
354
+ });
355
+ });
356
+ }
357
+
358
+ // Create grid for background
359
+ function createGrid() {
360
+ const spacing = 40;
361
+ const width = canvas.width;
362
+ const height = canvas.height;
363
+
364
+ for(let x = 0; x < width; x += spacing) {
365
+ gridLines.push({
366
+ x1: x,
367
+ y1: 0,
368
+ x2: x,
369
+ y2: height,
370
+ width: 1,
371
+ color: `rgba(255, 255, 255, ${Math.random() * 0.05 + 0.01})`
372
+ });
373
+ }
374
+
375
+ for(let y = 0; y < height; y += spacing) {
376
+ gridLines.push({
377
+ x1: 0,
378
+ y1: y,
379
+ x2: width,
380
+ y2: y,
381
+ width: 1,
382
+ color: `rgba(255, 255, 255, ${Math.random() * 0.05 + 0.01})`
383
+ });
384
+ }
385
+ }
386
+
387
+ // Draw grid background
388
+ function drawGrid() {
389
+ gridLines.forEach(line => {
390
+ ctx.beginPath();
391
+ ctx.moveTo(line.x1, line.y1);
392
+ ctx.lineTo(line.x2, line.y2);
393
+ ctx.strokeStyle = line.color;
394
+ ctx.lineWidth = line.width;
395
+ ctx.stroke();
396
+ });
397
+ }
398
+
399
+ // Create explosion particles
400
+ function createExplosion(x, y, color) {
401
+ for(let i = 0; i < 20; i++) {
402
+ particles.push({
403
+ x: x,
404
+ y: y,
405
+ radius: Math.random() * 6 + 2,
406
+ color: color || `hsl(${Math.random() * 20 + 20}, 100%, 50%)`,
407
+ speed: Math.random() * 5 + 2,
408
+ angle: Math.random() * Math.PI * 2,
409
+ life: Math.floor(Math.random() * 20 + 10),
410
+ decay: Math.random() * 0.1 + 0.05
411
+ });
412
+ }
413
+ }
414
+
415
+ // Create damage indicator
416
+ function createDamageIndicator(x, y, amount) {
417
+ particles.push({
418
+ x: x,
419
+ y: y,
420
+ radius: 0,
421
+ color: '#ffffff',
422
+ content: `-${amount}`,
423
+ textColor: '#ff0000',
424
+ textSize: 16,
425
+ life: 60,
426
+ decay: 1,
427
+ isText: true
428
+ });
429
+ }
430
+
431
+ // Update explosion particles
432
+ function updateParticles() {
433
+ for(let i = particles.length - 1; i >= 0; i--) {
434
+ const p = particles[i];
435
+
436
+ if (p.isText) {
437
+ p.y -= 1;
438
+ p.life -= p.decay;
439
+ } else {
440
+ p.x += Math.cos(p.angle) * p.speed;
441
+ p.y += Math.sin(p.angle) * p.speed;
442
+ p.speed *= 0.95;
443
+ p.life -= p.decay;
444
+ // Ensure radius doesn't become negative
445
+ p.radius = Math.max(0, p.radius - p.decay);
446
+ }
447
+
448
+ if(p.life <= 0) {
449
+ particles.splice(i, 1);
450
+ }
451
+ }
452
+ }
453
+
454
+ // Draw particles
455
+ function drawParticles() {
456
+ ctx.globalAlpha = 1;
457
+
458
+ particles.forEach(p => {
459
+ if (p.isText) {
460
+ ctx.font = `${p.textSize}px Arial`;
461
+ ctx.fillStyle = p.textColor;
462
+ // Text doesn't get affected by alpha in the same way
463
+ ctx.fillText(p.content, p.x, p.y);
464
+ } else {
465
+ // Only draw if radius is > 0
466
+ if (p.radius > 0) {
467
+ ctx.fillStyle = p.color;
468
+ ctx.beginPath();
469
+ ctx.arc(p.x, p.y, p.radius, 0, Math.PI*2);
470
+ ctx.fill();
471
+ }
472
+ }
473
+ });
474
+ }
475
+
476
+ // Tank class
477
+ class Tank {
478
+ constructor(x, y, color, isPlayer = false) {
479
+ this.x = x;
480
+ this.y = y;
481
+ this.width = 40;
482
+ this.height = 40;
483
+ this.color = color;
484
+ this.speed = isPlayer ? 4 : 2;
485
+ this.rotation = 0;
486
+ this.turretRotation = 0;
487
+ this.health = 100;
488
+ this.isPlayer = isPlayer;
489
+ this.lastShotTime = 0;
490
+ this.shotCooldown = isPlayer ? 400 : 1600;
491
+ this.bulletSpeed = isPlayer ? 10 : 7;
492
+ // Enemy AI properties
493
+ this.sightRange = isPlayer ? 0 : 400;
494
+ this.attackRange = isPlayer ? 0 : 250;
495
+ this.changeDirectionTime = 0;
496
+ this.currentDirection = 0;
497
+ this.retreating = false;
498
+ this.retreatTimer = 0;
499
+ this.healthCritical = false;
500
+ }
501
+
502
+ canMoveTo(newX, newY) {
503
+ // Convert world coordinate to obstacle map cell
504
+ const col = Math.floor(newX / 20);
505
+ const row = Math.floor(newY / 20);
506
+
507
+ // If any of the surrounding cells are obstacles, can't move here
508
+ return obstacleMap[row] && obstacleMap[row][col] === 0;
509
+ }
510
+
511
+ draw() {
512
+ ctx.save();
513
+ ctx.translate(this.x, this.y);
514
+
515
+ // Draw the tank body
516
+ ctx.rotate(this.rotation);
517
+ ctx.fillStyle = this.color;
518
+ ctx.fillRect(-this.width/2, -this.height/2, this.width, this.height);
519
+
520
+ // Draw turret
521
+ ctx.rotate(this.turretRotation - this.rotation);
522
+ ctx.fillStyle = this.isPlayer ? "#f1c40f" : "#e74c3c";
523
+ ctx.fillRect(this.width/2 - 10, -4, 25, 8);
524
+
525
+ ctx.restore();
526
+
527
+ // Draw health bar for enemies and player
528
+ if (this.health < 100) {
529
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
530
+ ctx.fillRect(this.x - 30, this.y - 35, 60, 6);
531
+ ctx.fillStyle = this.health > 30 ? '#2ecc71' : '#e74c3c';
532
+ ctx.fillRect(this.x - 30, this.y - 35, 60 * (this.health/100), 6);
533
+ }
534
+ }
535
+
536
+ update() {
537
+ if (this.isPlayer) {
538
+ this.updatePlayer();
539
+ } else {
540
+ this.updateEnemy();
541
+ }
542
+
543
+ // Keep tank within bounds
544
+ this.x = Math.max(this.width/2, Math.min(canvas.width - this.width/2, this.x));
545
+ this.y = Math.max(this.height/2, Math.min(canvas.height - this.height/2, this.y));
546
+ }
547
+
548
+ updatePlayer() {
549
+ let moveForward = false;
550
+ let moveBackward = false;
551
+ let rotateLeft = false;
552
+ let rotateRight = false;
553
+
554
+ // Movement controls
555
+ if (keys['ArrowUp'] || keys['w'] || keys['W']) moveForward = true;
556
+ if (keys['ArrowDown'] || keys['s'] || keys['S']) moveBackward = true;
557
+ if (keys['ArrowLeft'] || keys['a'] || keys['A']) rotateLeft = true;
558
+ if (keys['ArrowRight'] || keys['d'] || keys['D']) rotateRight = true;
559
+
560
+ // Mobile controls
561
+ if (mobileUp.classList.contains('active')) moveForward = true;
562
+ if (mobileDown.classList.contains('active')) moveBackward = true;
563
+ if (mobileLeft.classList.contains('active')) rotateLeft = true;
564
+ if (mobileRight.classList.contains('active')) rotateRight = true;
565
+
566
+ // Rotate body and turret together for player
567
+ if (rotateLeft) {
568
+ this.rotation -= 0.05;
569
+ }
570
+ if (rotateRight) {
571
+ this.rotation += 0.05;
572
+ }
573
+
574
+ // Move the tank
575
+ let newX = this.x, newY = this.y;
576
+
577
+ if (moveForward) {
578
+ newX = this.x + Math.cos(this.rotation) * this.speed;
579
+ newY = this.y + Math.sin(this.rotation) * this.speed;
580
+ }
581
+ if (moveBackward) {
582
+ newX = this.x - Math.cos(this.rotation) * this.speed;
583
+ newY = this.y - Math.sin(this.rotation) * this.speed;
584
+ }
585
+
586
+ // Check collision with obstacles
587
+ if (this.canMoveTo(newX, newY)) {
588
+ this.x = newX;
589
+ this.y = newY;
590
+ }
591
+
592
+ // Keep turrent rotation synchronized with body for player
593
+ this.turretRotation = this.rotation;
594
+
595
+ // Auto rotate the turret towards mouse
596
+ const mouseX = canvas.width/2;
597
+ const mouseY = canvas.height/2;
598
+ const angleToMouse = Math.atan2(mouseY - this.y, mouseX - this.x);
599
+ const angleDiff = this.normalizeAngle(angleToMouse - this.turretRotation);
600
+
601
+ if (Math.abs(angleDiff) > 0.05) {
602
+ this.turretRotation += angleDiff > 0 ? 0.05 : -0.05;
603
+ }
604
+ }
605
+
606
+ normalizeAngle(angle) {
607
+ while(angle > Math.PI) angle -= Math.PI * 2;
608
+ while(angle < -Math.PI) angle += Math.PI * 2;
609
+ return angle;
610
+ }
611
+
612
+ updateEnemy() {
613
+ // If player is destroyed, stop moving
614
+ if (!player) return;
615
+
616
+ // Calculate vector to player
617
+ const dx = player.x - this.x;
618
+ const dy = player.y - this.y;
619
+ const distance = Math.sqrt(dx * dx + dy * dy);
620
+
621
+ // Calculate the angle to the player
622
+ const angleToPlayer = Math.atan2(dy, dx);
623
+
624
+ // Set whether health is critical
625
+ this.healthCritical = this.health < 30;
626
+
627
+ // Retreat if health is critical and in close range
628
+ if (this.healthCritical && distance < this.attackRange * 0.6) {
629
+ this.retreating = true;
630
+ this.retreatTimer = 180;
631
+ }
632
+
633
+ if (this.retreatTimer > 0) {
634
+ this.retreatTimer--;
635
+ } else {
636
+ this.retreating = false;
637
+ }
638
+
639
+ // Point turret toward player
640
+ const angleDiff = this.normalizeAngle(angleToPlayer - this.turretRotation);
641
+
642
+ if (Math.abs(angleDiff) > 0.05) {
643
+ this.turretRotation += angleDiff > 0 ? 0.03 : -0.03;
644
+ }
645
+
646
+ // Movement logic
647
+ if (distance < this.sightRange && !this.healthCritical && !this.retreating) {
648
+ if (distance > this.attackRange * 0.8) {
649
+ // Approach player
650
+ this.x += Math.cos(angleToPlayer) * this.speed * 0.7;
651
+ this.y += Math.sin(angleToPlayer) * this.speed * 0.7;
652
+ } else if (distance < this.attackRange * 0.5) {
653
+ // Back up if too close
654
+ this.x -= Math.cos(angleToPlayer) * this.speed * 0.5;
655
+ this.y -= Math.sin(angleToPlayer) * this.speed * 0.5;
656
+ }
657
+
658
+ // Circle strafe occasionally
659
+ this.changeDirectionTime--;
660
+ if (this.changeDirectionTime <= 0) {
661
+ this.changeDirectionTime = Math.floor(Math.random() * 60) + 30;
662
+ this.currentDirection = Math.random() * 0.2 - 0.1;
663
+ if (Math.random() > 0.5) {
664
+ this.currentDirection *= -1;
665
+ }
666
+ }
667
+
668
+ // Circle strafing movement
669
+ this.x += Math.cos(angleToPlayer + Math.PI/2) * this.currentDirection * 2;
670
+ this.y += Math.sin(angleToPlayer + Math.PI/2) * this.currentDirection * 2;
671
+
672
+ // Try to maintain optimal attack range
673
+ if (distance > this.attackRange * 0.8 && distance < this.attackRange * 1.8) {
674
+ this.rotation = angleToPlayer;
675
+ }
676
+ } else if (this.retreating) {
677
+ // Run away if retreating
678
+ this.x -= Math.cos(angleToPlayer) * this.speed;
679
+ this.y -= Math.sin(angleToPlayer) * this.speed;
680
+ this.rotation = angleToPlayer + Math.PI;
681
+ } else {
682
+ // Patrol randomly
683
+ this.changeDirectionTime--;
684
+ if (this.changeDirectionTime <= 0 ||
685
+ this.x < 50 || this.x > canvas.width - 50 ||
686
+ this.y < 50 || this.y > canvas.height - 50) {
687
+
688
+ this.changeDirectionTime = Math.floor(Math.random() * 60) + 30;
689
+ this.rotation = Math.random() * Math.PI * 2;
690
+ }
691
+
692
+ this.x += Math.cos(this.rotation) * this.speed * 0.5;
693
+ this.y += Math.sin(this.rotation) * this.speed * 0.5;
694
+ }
695
+
696
+ // Shoot at player if in attack range
697
+ if (distance < this.attackRange && Math.abs(angleDiff) < 0.2) {
698
+ const now = Date.now();
699
+ if (now - this.lastShotTime > this.shotCooldown) {
700
+ this.shoot();
701
+ this.lastShotTime = now;
702
+ }
703
+ }
704
+ }
705
+
706
+ shoot() {
707
+ const bulletX = this.x + Math.cos(this.turretRotation) * (this.width/2 + 15);
708
+ const bulletY = this.y + Math.sin(this.turretRotation) * (this.height/2 + 15);
709
+
710
+ bullets.push({
711
+ x: bulletX,
712
+ y: bulletY,
713
+ angle: this.turretRotation,
714
+ speed: this.bulletSpeed,
715
+ isPlayer: this.isPlayer,
716
+ damage: this.isPlayer ? 100 : 25, // Player bullets do 100 damage (one-shot kill)
717
+ size: this.isPlayer ? 8 : 6, // Player bullets are larger - visual feedback for one-shot
718
+ color: this.isPlayer ? '#f1c40f' : '#e74c3c'
719
+ });
720
+
721
+ // Player bullet sound effect
722
+ if (this.isPlayer) {
723
+ createExplosion(bulletX, bulletY, '#f1c40f');
724
+ }
725
+ }
726
+
727
+ takeDamage(amount) {
728
+ const damageTaken = amount;
729
+ this.health -= amount;
730
+
731
+ if (this.isPlayer) {
732
+ createDamageIndicator(this.x, this.y, damageTaken);
733
+ }
734
+
735
+ if (this.health <= 0) {
736
+ this.destroy();
737
+ return true;
738
+ }
739
+ return false;
740
+ }
741
+
742
+ destroy() {
743
+ createExplosion(this.x, this.y);
744
+
745
+ if (this.isPlayer) {
746
+ gameOver();
747
+ } else {
748
+ score += 100;
749
+ comboCounter++;
750
+
751
+ // Apply combo bonus
752
+ if (comboCounter > 1) {
753
+ const bonus = comboCounter * 25;
754
+ score += bonus;
755
+ createDamageIndicator(this.x, this.y, `+${bonus} Combo!`, '#00ff00');
756
+ }
757
+
758
+ // Reset combo timer
759
+ clearTimeout(comboTimeout);
760
+ comboTimeout = setTimeout(() => {
761
+ comboCounter = 0;
762
+ }, 2000);
763
+
764
+ scoreDisplay.textContent = score;
765
+ enemiesDisplay.textContent = enemies.length - 1;
766
+ }
767
+ }
768
+ }
769
+
770
+ // Initialize game
771
+ function initGame() {
772
+ player = new Tank(canvas.width/2, canvas.height/2, tankColors.player, true);
773
+ enemies = [];
774
+ bullets = [];
775
+ particles = [];
776
+ score = 0;
777
+ scoreDisplay.textContent = score;
778
+ healthDisplay.textContent = player.health;
779
+ enemiesDisplay.textContent = 0;
780
+ gameTime = 0;
781
+ enemySpawnTimer = 0;
782
+ comboCounter = 0;
783
+
784
+ generateObstacleMap();
785
+ createGrid();
786
+
787
+ // Spawn initial enemies
788
+ for (let i = 0; i < 2; i++) {
789
+ spawnEnemy();
790
+ }
791
+ }
792
+
793
+ // Spawn enemy
794
+ function spawnEnemy() {
795
+ let x, y;
796
+ // Spawn at semi-random edge position with obstacle check
797
+ let safePosition = false;
798
+ let attempts = 0;
799
+
800
+ while (!safePosition && attempts < 20) {
801
+ const side = Math.floor(Math.random() * 4);
802
+ const pos = Math.random() * 0.6 + 0.2;
803
+
804
+ switch(side) {
805
+ case 0: // top
806
+ x = canvas.width * pos;
807
+ y = -40;
808
+ break;
809
+ case 1: // right
810
+ x = canvas.width + 40;
811
+ y = canvas.height * pos;
812
+ break;
813
+ case 2: // bottom
814
+ x = canvas.width * pos;
815
+ y = canvas.height + 40;
816
+ break;
817
+ case 3: // left
818
+ x = -40;
819
+ y = canvas.height * pos;
820
+ break;
821
+ }
822
+
823
+ // Ensure enemy doesn't spawn in a wall
824
+ const col = Math.floor(x / 20);
825
+ const row = Math.floor(y / 20);
826
+
827
+ if (obstacleMap[row] && obstacleMap[row][col] === 0) {
828
+ safePosition = true;
829
+ }
830
+
831
+ attempts++;
832
+ }
833
+
834
+ const enemy = new Tank(x, y, tankColors.enemy);
835
+ enemies.push(enemy);
836
+ enemiesDisplay.textContent = enemies.length;
837
+ }
838
+
839
+ // Check collision between two objects
840
+ function checkCollision(obj1, obj2) {
841
+ const distX = Math.abs(obj1.x - obj2.x);
842
+ const distY = Math.abs(obj1.y - obj2.y);
843
+ let distance;
844
+
845
+ if (obj1.width && obj2.width) {
846
+ // Tank-tank collision
847
+ return distX < (obj1.width/2 + obj2.width/2) &&
848
+ distY < (obj1.height/2 + obj2.height/2);
849
+ } else {
850
+ // Bullet-tank collision
851
+ distance = Math.sqrt(distX * distX + distY * distY);
852
+ return distance < (obj2.width/2) + (obj1.size || 4);
853
+ }
854
+ }
855
+
856
+ // Game over
857
+ function gameOver() {
858
+ gameRunning = false;
859
+ gameOverScreen.classList.remove('hidden');
860
+ finalScore.textContent = score;
861
+ }
862
+
863
+ // Main game loop
864
+ function gameLoop() {
865
+ if (!gameRunning || isPaused) return;
866
+
867
+ // Clear canvas
868
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
869
+
870
+ // Draw background grid and obstacles
871
+ drawGrid();
872
+ drawObstacles();
873
+
874
+ // Update and draw player
875
+ player.update();
876
+ player.draw();
877
+ healthDisplay.textContent = player.health;
878
+
879
+ // Draw and update enemies
880
+ enemies.forEach(enemy => {
881
+ enemy.update();
882
+ enemy.draw();
883
+ });
884
+
885
+ // Update and draw particles
886
+ updateParticles();
887
+ drawParticles();
888
+
889
+ // Update and draw bullets
890
+ for (let i = bullets.length - 1; i >= 0; i--) {
891
+ const bullet = bullets[i];
892
+ bullet.x += Math.cos(bullet.angle) * bullet.speed;
893
+ bullet.y += Math.sin(bullet.angle) * bullet.speed;
894
+
895
+ // Draw bullet with glow for player bullets
896
+ ctx.fillStyle = bullet.color;
897
+
898
+ // Player bullets are visually distinct (bigger and glowing)
899
+ if (bullet.isPlayer) {
900
+ ctx.shadowBlur = 10;
901
+ ctx.shadowColor = bullet.color;
902
+ ctx.beginPath();
903
+ ctx.arc(bullet.x, bullet.y, bullet.size || 6, 0, Math.PI*2);
904
+ ctx.fill();
905
+ ctx.shadowBlur = 0;
906
+ } else {
907
+ ctx.beginPath();
908
+ ctx.arc(bullet.x, bullet.y, bullet.size || 4, 0, Math.PI*2);
909
+ ctx.fill();
910
+ }
911
+
912
+ // Check obstacle collisions
913
+ const col = Math.floor(bullet.x / 20);
914
+ const row = Math.floor(bullet.y / 20);
915
+
916
+ if (obstacleMap[row] && obstacleMap[row][col] === 1) {
917
+ // Create impact explosion or spark
918
+ createExplosion(bullet.x, bullet.y, bullet.color);
919
+ bullets.splice(i, 1);
920
+ continue;
921
+ }
922
+
923
+ // Check collisions with tanks
924
+ if (bullet.isPlayer) {
925
+ // Player bullet hits enemy
926
+ for (let j = enemies.length - 1; j >= 0; j--) {
927
+ const enemy = enemies[j];
928
+ if (checkCollision(bullet, enemy)) {
929
+ createExplosion(bullet.x, bullet.y, bullet.color);
930
+ enemy.takeDamage(bullet.damage); // This destroys enemy (100 damage)
931
+ bullets.splice(i, 1);
932
+ break;
933
+ }
934
+ }
935
+ } else {
936
+ // Enemy bullet hits player
937
+ if (checkCollision(bullet, player)) {
938
+ createExplosion(bullet.x, bullet.y, bullet.color);
939
+ if (player.takeDamage(bullet.damage)) {
940
+ player = null;
941
+ }
942
+ bullets.splice(i, 1);
943
+ }
944
+ }
945
+
946
+ // Remove bullets that are out of bounds
947
+ if (bullet.x < -50 || bullet.x > canvas.width + 50 ||
948
+ bullet.y < -50 || bullet.y > canvas.height + 50) {
949
+ bullets.splice(i, 1);
950
+ }
951
+ }
952
+
953
+ // Spawn new enemies periodically
954
+ gameTime++;
955
+ enemySpawnTimer++;
956
+ if (enemySpawnTimer > 120) {
957
+ if (enemies.length < 6 + Math.floor(gameTime / 300)) {
958
+ spawnEnemy();
959
+ }
960
+ enemySpawnTimer = 0;
961
+ }
962
+
963
+ // Increase difficulty over time
964
+ if (gameTime % 300 === 0 && player.health < 75) {
965
+ player.health += 5;
966
+ healthDisplay.textContent = player.health;
967
+ createDamageIndicator(player.x, player.y+30, "+5 HP", '#00ff00');
968
+ }
969
+
970
+ requestAnimationFrame(gameLoop);
971
+ }
972
+
973
+ // Event listeners for keyboard controls
974
+ window.addEventListener('keydown', (e) => {
975
+ keys[e.key] = true;
976
+
977
+ // Space to shoot
978
+ if (e.key === ' ' && gameRunning && player && Date.now() - lastShotTime > 500) {
979
+ lastShotTime = Date.now();
980
+ player.shoot();
981
+ }
982
+ });
983
+
984
+ window.addEventListener('keyup', (e) => {
985
+ keys[e.key] = false;
986
+ });
987
+
988
+ // Mobile control event listeners
989
+ mobileUp.addEventListener('touchstart', (e) => {
990
+ mobileUp.classList.add('active');
991
+ e.preventDefault();
992
+ }, {passive: false});
993
+
994
+ mobileDown.addEventListener('touchstart', (e) => {
995
+ mobileDown.classList.add('active');
996
+ e.preventDefault();
997
+ }, {passive: false});
998
+
999
+ mobileLeft.addEventListener('touchstart', (e) => {
1000
+ mobileLeft.classList.add('active');
1001
+ e.preventDefault();
1002
+ }, {passive: false});
1003
+
1004
+ mobileRight.addEventListener('touchstart', (e) => {
1005
+ mobileRight.classList.add('active');
1006
+ e.preventDefault();
1007
+ }, {passive: false});
1008
+
1009
+ mobileShoot.addEventListener('touchstart', (e) => {
1010
+ mobileShoot.classList.add('active');
1011
+ if (gameRunning && player && Date.now() - lastShotTime > 500) {
1012
+ player.shoot();
1013
+ lastShotTime = Date.now();
1014
+ }
1015
+ e.preventDefault();
1016
+ }, {passive: false});
1017
+
1018
+ // Mobile touch end listeners
1019
+ const mobileButtons = [mobileUp, mobileDown, mobileLeft, mobileRight, mobileShoot];
1020
+ mobileButtons.forEach(btn => {
1021
+ btn.addEventListener('touchend', () => {
1022
+ btn.classList.remove('active');
1023
+ });
1024
+ btn.addEventListener('touchcancel', () => {
1025
+ btn.classList.remove('active');
1026
+ });
1027
+ });
1028
+
1029
+ // Start button
1030
+ startBtn.addEventListener('click', () => {
1031
+ startScreen.classList.add('hidden');
1032
+ gameRunning = true;
1033
+ initGame();
1034
+ gameLoop();
1035
+ mobileControls.classList.remove('hidden');
1036
+ });
1037
+
1038
+ // Restart button
1039
+ restartBtn.addEventListener('click', () => {
1040
+ gameOverScreen.classList.add('hidden');
1041
+ gameRunning = true;
1042
+ initGame();
1043
+ gameLoop();
1044
+ mobileControls.classList.remove('hidden');
1045
+ });
1046
+
1047
+ // Pause button
1048
+ pauseBtn.addEventListener('click', () => {
1049
+ isPaused = !isPaused;
1050
+ pauseBtn.innerHTML = isPaused ?
1051
+ '<i class="fas fa-play mr-2"></i>Resume' :
1052
+ '<i class="fas fa-pause mr-2"></i>Pause';
1053
+ });
1054
+
1055
+ // Handle mouse movement for turret
1056
+ canvas.addEventListener('mousemove', () => {
1057
+ if (!player) return;
1058
+
1059
+ const mouseX = canvas.width/2;
1060
+ const mouseY = canvas.height/2;
1061
+ player.turretRotation = Math.atan2(mouseY - player.y, mouseX - player.x);
1062
+ });
1063
+
1064
+ // Mobile touch events
1065
+ canvas.addEventListener('click', (e) => {
1066
+ if (gameRunning && player && Date.now() - lastShotTime > 500) {
1067
+ lastShotTime = Date.now();
1068
+ player.shoot();
1069
+ }
1070
+ });
1071
+
1072
+ // Handle window resize
1073
+ window.addEventListener('resize', () => {
1074
+ canvas.width = canvas.offsetWidth;
1075
+ canvas.height = canvas.offsetHeight;
1076
+ gridLines = [];
1077
+ createGrid();
1078
+ generateObstacleMap();
1079
+ });
1080
+
1081
+ // Check if mobile and touch devices
1082
+ const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
1083
+ if (!('ontouchstart' in window) && !isMobile) {
1084
+ mobileControls.classList.add('hidden');
1085
+ } else {
1086
+ // For touch devices, start with controls hidden until game starts
1087
+ mobileControls.classList.add('hidden');
1088
+ }
1089
+
1090
+ // Show start screen on initial load
1091
+ window.onload = () => {
1092
+ startScreen.classList.remove('hidden');
1093
+ canvas.width = canvas.offsetWidth;
1094
+ canvas.height = canvas.offsetHeight;
1095
+ firepowerDisplay.textContent = "INSTANT";
1096
+ };
1097
+ </script>
1098
+ <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=Dragoy/tank-battle-royale-one-shot" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1099
+ </html>
prompts.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ write me a tank game in html css js Add enemies write intelligence for them to attack me and chase me.
2
+ write me a tank game in html css js Add enemies write intelligence for them to attack me and chase me.
3
+ убийство врагом с одного попадания
4
+ убийство врагов с одного моего попадания что бы снизить сложность
5
+ Uncaught IndexSizeError: Failed to execute 'arc' on 'CanvasRenderingContext2D': The radius provided (-0.0320748) is negative. at about:srcdoc:465:25 at Array.forEach (<anonymous>) at drawParticles (about:srcdoc:455:23) at gameLoop (about:srcdoc:883:13)