Mohabedalgani commited on
Commit
7a2efe0
·
verified ·
1 Parent(s): 252bfbe

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +375 -326
index.html CHANGED
@@ -3,13 +3,15 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Brick Attacker Game</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
 
8
  <style>
9
  #gameCanvas {
10
  background-color: #1a202c;
11
  border-radius: 8px;
12
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 
13
  }
14
 
15
  .game-container {
@@ -42,11 +44,113 @@
42
  .heart-icon {
43
  color: #f56565;
44
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  </style>
46
  </head>
47
  <body class="bg-gray-900 min-h-screen flex flex-col items-center justify-center p-4">
48
  <div class="max-w-4xl w-full">
49
- <h1 class="text-3xl font-bold text-center text-white mb-6">Brick Attacker</h1>
50
 
51
  <div class="flex justify-between items-center mb-4">
52
  <div class="flex items-center space-x-2">
@@ -56,386 +160,331 @@
56
  <div class="flex items-center space-x-2">
57
  <span class="text-white font-semibold">Lives:</span>
58
  <div id="lives" class="flex space-x-1">
59
- <!-- Hearts will be added here by JavaScript -->
 
 
60
  </div>
61
  </div>
62
  </div>
63
 
64
  <div class="game-container relative">
65
- <canvas id="gameCanvas" width="800" height="500"></canvas>
66
 
67
  <div id="startScreen" class="game-overlay">
68
  <h2 class="text-4xl font-bold mb-6 text-yellow-300">Brick Attacker</h2>
69
- <p class="text-xl mb-8 text-center max-w-md">Use your mouse or arrow keys to move the paddle.<br>Break all bricks to win!</p>
70
- <button id="startButton" class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-8 rounded-full text-xl transition duration-200 transform hover:scale-105">
71
- Start Game
72
  </button>
73
  </div>
74
 
75
  <div id="gameOverScreen" class="game-overlay hidden">
76
  <h2 class="text-4xl font-bold mb-4 text-red-500">Game Over</h2>
77
  <p class="text-2xl mb-2">Your score: <span id="finalScore" class="text-yellow-300">0</span></p>
78
- <button id="restartButton" class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-6 rounded-full text-lg mt-6 transition duration-200 transform hover:scale-105">
79
- Play Again
80
- </button>
81
- </div>
82
-
83
- <div id="winScreen" class="game-overlay hidden">
84
- <h2 class="text-4xl font-bold mb-4 text-green-400">You Win!</h2>
85
- <p class="text-2xl mb-2">Your score: <span id="winScore" class="text-yellow-300">0</span></p>
86
- <button id="winRestartButton" class="bg-purple-500 hover:bg-purple-600 text-white font-bold py-2 px-6 rounded-full text-lg mt-6 transition duration-200 transform hover:scale-105">
87
- Play Again
88
  </button>
89
  </div>
90
  </div>
91
 
92
- <div class="mt-6 text-center text-gray-400">
93
- <p>Controls: Mouse movement or Left/Right arrow keys</p>
 
 
 
 
 
 
 
94
  </div>
95
  </div>
96
 
97
  <script>
98
- document.addEventListener('DOMContentLoaded', () => {
99
- // Game elements
100
- const canvas = document.getElementById('gameCanvas');
101
- const ctx = canvas.getContext('2d');
102
- const scoreElement = document.getElementById('score');
103
- const livesElement = document.getElementById('lives');
104
- const startScreen = document.getElementById('startScreen');
105
- const gameOverScreen = document.getElementById('gameOverScreen');
106
- const winScreen = document.getElementById('winScreen');
107
- const startButton = document.getElementById('startButton');
108
- const restartButton = document.getElementById('restartButton');
109
- const winRestartButton = document.getElementById('winRestartButton');
110
- const finalScoreElement = document.getElementById('finalScore');
111
- const winScoreElement = document.getElementById('winScore');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
- // Game variables
114
- let score = 0;
115
- let lives = 3;
116
- let gameRunning = false;
117
- let animationId;
118
 
119
- // Game objects
120
- const ball = {
121
- x: canvas.width / 2,
122
- y: canvas.height - 30,
123
- radius: 10,
124
- dx: 4,
125
- dy: -4,
126
- color: '#f56565'
127
- };
128
 
129
- const paddle = {
130
- width: 100,
131
- height: 15,
132
- x: canvas.width / 2 - 50,
133
- speed: 8,
134
- color: '#4299e1'
135
- };
 
 
 
 
 
 
 
 
 
 
136
 
137
- const brick = {
138
- rowCount: 5,
139
- columnCount: 10,
140
- width: 75,
141
- height: 20,
142
- padding: 10,
143
- offsetTop: 50,
144
- offsetLeft: 30,
145
- colors: ['#48bb78', '#f6ad55', '#9f7aea', '#f687b3', '#4fd1c5']
146
- };
147
 
148
- let bricks = [];
 
149
 
150
- // Initialize bricks
151
- function initBricks() {
152
- bricks = [];
153
- for (let c = 0; c < brick.columnCount; c++) {
154
- bricks[c] = [];
155
- for (let r = 0; r < brick.rowCount; r++) {
156
- bricks[c][r] = { x: 0, y: 0, status: 1, color: brick.colors[r % brick.colors.length] };
157
- }
158
- }
159
- }
160
 
161
- // Draw ball
162
- function drawBall() {
163
- ctx.beginPath();
164
- ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
165
- ctx.fillStyle = ball.color;
166
- ctx.fill();
167
- ctx.closePath();
168
- }
169
 
170
- // Draw paddle
171
- function drawPaddle() {
172
- ctx.beginPath();
173
- ctx.roundRect(paddle.x, canvas.height - paddle.height - 10, paddle.width, paddle.height, 8);
174
- ctx.fillStyle = paddle.color;
175
- ctx.fill();
176
- ctx.closePath();
177
- }
178
 
179
- // Draw bricks
180
- function drawBricks() {
181
- for (let c = 0; c < brick.columnCount; c++) {
182
- for (let r = 0; r < brick.rowCount; r++) {
183
- if (bricks[c][r].status === 1) {
184
- const brickX = c * (brick.width + brick.padding) + brick.offsetLeft;
185
- const brickY = r * (brick.height + brick.padding) + brick.offsetTop;
186
- bricks[c][r].x = brickX;
187
- bricks[c][r].y = brickY;
188
-
189
- ctx.beginPath();
190
- ctx.roundRect(brickX, brickY, brick.width, brick.height, 2);
191
- ctx.fillStyle = bricks[c][r].color;
192
- ctx.fill();
193
- ctx.closePath();
194
- }
195
- }
196
- }
197
- }
198
 
199
- // Collision detection
200
- function collisionDetection() {
201
- for (let c = 0; c < brick.columnCount; c++) {
202
- for (let r = 0; r < brick.rowCount; r++) {
203
- const b = bricks[c][r];
204
- if (b.status === 1) {
205
- if (
206
- ball.x + ball.radius > b.x &&
207
- ball.x - ball.radius < b.x + brick.width &&
208
- ball.y + ball.radius > b.y &&
209
- ball.y - ball.radius < b.y + brick.height
210
- ) {
211
- ball.dy = -ball.dy;
212
- b.status = 0;
213
- score += 10;
214
- scoreElement.textContent = score;
215
-
216
- // Check if all bricks are broken
217
- if (checkWin()) {
218
- gameWin();
219
- }
220
- }
221
- }
222
- }
223
- }
224
  }
225
 
226
- // Check if all bricks are broken
227
- function checkWin() {
228
- for (let c = 0; c < brick.columnCount; c++) {
229
- for (let r = 0; r < brick.rowCount; r++) {
230
- if (bricks[c][r].status === 1) {
231
- return false;
232
- }
233
- }
234
- }
235
- return true;
236
- }
237
 
238
- // Update lives display
239
- function updateLivesDisplay() {
240
- livesElement.innerHTML = '';
241
- for (let i = 0; i < lives; i++) {
242
- livesElement.innerHTML += `
243
- <svg class="heart-icon w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
244
- <path fill-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clip-rule="evenodd"></path>
245
- </svg>
246
- `;
247
- }
248
- }
249
 
250
- // Main game loop
251
- function draw() {
252
- // Clear canvas
253
- ctx.clearRect(0, 0, canvas.width, canvas.height);
254
-
255
- // Draw game objects
256
- drawBricks();
257
- drawBall();
258
- drawPaddle();
259
-
260
- // Collision detection
261
- collisionDetection();
262
-
263
- // Wall collision (left/right)
264
- if (ball.x + ball.dx > canvas.width - ball.radius || ball.x + ball.dx < ball.radius) {
265
- ball.dx = -ball.dx;
266
- }
267
-
268
- // Wall collision (top)
269
- if (ball.y + ball.dy < ball.radius) {
270
- ball.dy = -ball.dy;
271
- }
272
- // Paddle collision
273
- else if (
274
- ball.y + ball.dy > canvas.height - ball.radius - paddle.height - 10 &&
275
- ball.x > paddle.x &&
276
- ball.x < paddle.x + paddle.width
277
- ) {
278
- // Calculate bounce angle based on where ball hits paddle
279
- const hitPosition = (ball.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2);
280
- const angle = hitPosition * Math.PI / 3; // Max 60 degrees
281
-
282
- ball.dx = 5 * Math.sin(angle);
283
- ball.dy = -Math.abs(5 * Math.cos(angle));
284
- }
285
- // Bottom wall collision (lose life)
286
- else if (ball.y + ball.dy > canvas.height - ball.radius) {
287
- lives--;
288
- updateLivesDisplay();
289
-
290
- if (lives <= 0) {
291
- gameOver();
292
- } else {
293
- // Reset ball and paddle
294
- ball.x = canvas.width / 2;
295
- ball.y = canvas.height - 30;
296
- ball.dx = 4 * (Math.random() > 0.5 ? 1 : -1);
297
- ball.dy = -4;
298
- paddle.x = canvas.width / 2 - paddle.width / 2;
299
- }
300
- }
301
-
302
- // Move ball
303
- ball.x += ball.dx;
304
- ball.y += ball.dy;
305
-
306
- // Continue animation
307
- if (gameRunning) {
308
- animationId = requestAnimationFrame(draw);
309
- }
310
  }
311
 
312
- // Keyboard controls
313
- let rightPressed = false;
314
- let leftPressed = false;
 
 
 
 
 
315
 
316
- document.addEventListener('keydown', (e) => {
317
- if (e.key === 'Right' || e.key === 'ArrowRight') {
318
- rightPressed = true;
319
- } else if (e.key === 'Left' || e.key === 'ArrowLeft') {
320
- leftPressed = true;
321
- }
322
- });
323
 
324
- document.addEventListener('keyup', (e) => {
325
- if (e.key === 'Right' || e.key === 'ArrowRight') {
326
- rightPressed = false;
327
- } else if (e.key === 'Left' || e.key === 'ArrowLeft') {
328
- leftPressed = false;
329
- }
 
 
330
  });
331
-
332
- // Mouse controls
333
- document.addEventListener('mousemove', (e) => {
334
- if (!gameRunning) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
- const relativeX = e.clientX - canvas.offsetLeft;
337
- if (relativeX > paddle.width / 2 && relativeX < canvas.width - paddle.width / 2) {
338
- paddle.x = relativeX - paddle.width / 2;
339
- }
340
- });
341
-
342
- // Touch controls for mobile
343
- document.addEventListener('touchmove', (e) => {
344
- if (!gameRunning) return;
345
- e.preventDefault();
346
 
347
- const touch = e.touches[0];
348
- const relativeX = touch.clientX - canvas.offsetLeft;
349
- if (relativeX > paddle.width / 2 && relativeX < canvas.width - paddle.width / 2) {
350
- paddle.x = relativeX - paddle.width / 2;
 
 
 
 
 
 
351
  }
352
- }, { passive: false });
353
-
354
- // Update paddle position based on keyboard input
355
- function updatePaddlePosition() {
356
- if (rightPressed && paddle.x < canvas.width - paddle.width) {
357
- paddle.x += paddle.speed;
358
- } else if (leftPressed && paddle.x > 0) {
359
- paddle.x -= paddle.speed;
360
  }
361
  }
362
-
363
- // Game over
364
- function gameOver() {
365
- gameRunning = false;
366
- cancelAnimationFrame(animationId);
367
- finalScoreElement.textContent = score;
368
- gameOverScreen.classList.remove('hidden');
369
- }
370
-
371
- // Game win
372
- function gameWin() {
373
- gameRunning = false;
374
- cancelAnimationFrame(animationId);
375
- winScoreElement.textContent = score;
376
- winScreen.classList.remove('hidden');
377
- }
378
-
379
- // Reset game
380
- function resetGame() {
381
- score = 0;
382
- lives = 3;
383
- scoreElement.textContent = score;
384
- updateLivesDisplay();
385
 
386
- ball.x = canvas.width / 2;
387
- ball.y = canvas.height - 30;
388
- ball.dx = 4 * (Math.random() > 0.5 ? 1 : -1);
389
- ball.dy = -4;
 
 
390
 
391
- paddle.x = canvas.width / 2 - paddle.width / 2;
 
 
 
 
 
392
 
393
- initBricks();
 
 
 
 
394
  }
395
-
396
- // Start game
397
- function startGame() {
398
- resetGame();
399
- startScreen.classList.add('hidden');
400
- gameOverScreen.classList.add('hidden');
401
- winScreen.classList.add('hidden');
402
- gameRunning = true;
403
- draw();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  }
 
 
 
 
405
 
406
- // Event listeners for buttons
407
- startButton.addEventListener('click', startGame);
408
- restartButton.addEventListener('click', startGame);
409
- winRestartButton.addEventListener('click', startGame);
410
 
411
- // Initialize game
412
- updateLivesDisplay();
 
 
 
 
 
 
 
 
 
413
 
414
- // Make canvas responsive
415
- function resizeCanvas() {
416
- const container = document.querySelector('.game-container');
417
- const containerWidth = container.clientWidth;
418
-
419
- // Maintain aspect ratio (16:10)
420
- canvas.width = Math.min(800, containerWidth);
421
- canvas.height = (canvas.width * 5) / 8;
422
-
423
- // Adjust ball and paddle size based on canvas size
424
- ball.radius = canvas.width / 80;
425
- paddle.width = canvas.width / 8;
426
- paddle.height = canvas.height / 35;
427
-
428
- // Reset game objects
429
- if (!gameRunning) {
430
- ball.x = canvas.width / 2;
431
- ball.y = canvas.height - 30;
432
- paddle.x = canvas.width / 2 - paddle.width / 2;
433
- }
434
  }
 
 
 
 
 
435
 
436
- window.addEventListener('resize', resizeCanvas);
437
- resizeCanvas();
438
- });
439
  </script>
440
  <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=Mohabedalgani/zaido" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
441
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Moving Brick Attacker</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
  #gameCanvas {
11
  background-color: #1a202c;
12
  border-radius: 8px;
13
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
14
+ touch-action: none;
15
  }
16
 
17
  .game-container {
 
44
  .heart-icon {
45
  color: #f56565;
46
  }
47
+
48
+ .bullet {
49
+ position: absolute;
50
+ width: 4px;
51
+ height: 12px;
52
+ background-color: #f6e05e;
53
+ border-radius: 2px;
54
+ }
55
+
56
+ #attacker {
57
+ position: absolute;
58
+ width: 50px;
59
+ height: 80px;
60
+ background-color: #4a5568;
61
+ border-radius: 8px;
62
+ bottom: 10px;
63
+ left: 50%;
64
+ transform: translateX(-50%);
65
+ z-index: 10;
66
+ }
67
+
68
+ #gun {
69
+ position: absolute;
70
+ width: 30px;
71
+ height: 10px;
72
+ background-color: #2d3748;
73
+ top: -10px;
74
+ left: 10px;
75
+ border-radius: 2px;
76
+ transform-origin: left center;
77
+ z-index: 20;
78
+ }
79
+
80
+ #gun-barrel {
81
+ position: absolute;
82
+ width: 30px;
83
+ height: 4px;
84
+ background-color: #2d3748;
85
+ top: 3px;
86
+ left: 30px;
87
+ border-radius: 2px;
88
+ }
89
+
90
+ /* Animation for special bricks */
91
+ @keyframes pulse {
92
+ 0% { transform: scale(1); }
93
+ 50% { transform: scale(1.05); }
94
+ 100% { transform: scale(1); }
95
+ }
96
+
97
+ @keyframes spin {
98
+ 0% { transform: rotate(0deg); }
99
+ 100% { transform: rotate(360deg); }
100
+ }
101
+
102
+ .start-btn {
103
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
104
+ border: none;
105
+ color: white;
106
+ padding: 15px 32px;
107
+ text-align: center;
108
+ text-decoration: none;
109
+ display: inline-block;
110
+ font-size: 18px;
111
+ font-weight: bold;
112
+ margin: 10px 2px;
113
+ cursor: pointer;
114
+ border-radius: 50px;
115
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
116
+ transition: all 0.3s ease;
117
+ position: relative;
118
+ overflow: hidden;
119
+ }
120
+
121
+ .start-btn:hover {
122
+ transform: translateY(-3px);
123
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
124
+ }
125
+
126
+ .start-btn:active {
127
+ transform: translateY(1px);
128
+ }
129
+
130
+ .start-btn::after {
131
+ content: "";
132
+ position: absolute;
133
+ top: 0;
134
+ left: 0;
135
+ width: 100%;
136
+ height: 100%;
137
+ background: linear-gradient(135deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0) 100%);
138
+ opacity: 0;
139
+ transition: opacity 0.3s ease;
140
+ }
141
+
142
+ .start-btn:hover::after {
143
+ opacity: 1;
144
+ }
145
+
146
+ .start-btn i {
147
+ margin-right: 10px;
148
+ }
149
  </style>
150
  </head>
151
  <body class="bg-gray-900 min-h-screen flex flex-col items-center justify-center p-4">
152
  <div class="max-w-4xl w-full">
153
+ <h1 class="text-3xl font-bold text-center text-white mb-6">Moving Brick Attacker</h1>
154
 
155
  <div class="flex justify-between items-center mb-4">
156
  <div class="flex items-center space-x-2">
 
160
  <div class="flex items-center space-x-2">
161
  <span class="text-white font-semibold">Lives:</span>
162
  <div id="lives" class="flex space-x-1">
163
+ <i class="fas fa-heart heart-icon"></i>
164
+ <i class="fas fa-heart heart-icon"></i>
165
+ <i class="fas fa-heart heart-icon"></i>
166
  </div>
167
  </div>
168
  </div>
169
 
170
  <div class="game-container relative">
171
+ <canvas id="gameCanvas" width="800" height="500" class="w-full"></canvas>
172
 
173
  <div id="startScreen" class="game-overlay">
174
  <h2 class="text-4xl font-bold mb-6 text-yellow-300">Brick Attacker</h2>
175
+ <p class="text-xl mb-8 text-center max-w-md">Shoot the moving bricks before they reach the bottom!</p>
176
+ <button id="startButton" class="start-btn">
177
+ <i class="fas fa-play"></i> Start Game
178
  </button>
179
  </div>
180
 
181
  <div id="gameOverScreen" class="game-overlay hidden">
182
  <h2 class="text-4xl font-bold mb-4 text-red-500">Game Over</h2>
183
  <p class="text-2xl mb-2">Your score: <span id="finalScore" class="text-yellow-300">0</span></p>
184
+ <button id="restartButton" class="start-btn mt-6">
185
+ <i class="fas fa-redo"></i> Play Again
 
 
 
 
 
 
 
 
186
  </button>
187
  </div>
188
  </div>
189
 
190
+ <div class="mt-6 flex justify-center">
191
+ <div class="bg-gray-800 p-4 rounded-lg max-w-md">
192
+ <h3 class="text-white font-semibold mb-2">Controls:</h3>
193
+ <ul class="text-gray-300 space-y-1">
194
+ <li><i class="fas fa-mouse-pointer mr-2"></i> Move mouse to aim</li>
195
+ <li><i class="fas fa-mouse mr-2"></i> Click to shoot</li>
196
+ <li><i class="fas fa-arrows-alt mr-2"></i> Arrow keys to move</li>
197
+ </ul>
198
+ </div>
199
  </div>
200
  </div>
201
 
202
  <script>
203
+ // Game variables
204
+ const canvas = document.getElementById('gameCanvas');
205
+ const ctx = canvas.getContext('2d');
206
+ const startScreen = document.getElementById('startScreen');
207
+ const gameOverScreen = document.getElementById('gameOverScreen');
208
+ const startButton = document.getElementById('startButton');
209
+ const restartButton = document.getElementById('restartButton');
210
+ const scoreElement = document.getElementById('score');
211
+ const finalScoreElement = document.getElementById('finalScore');
212
+ const livesElement = document.getElementById('lives');
213
+
214
+ let gameRunning = false;
215
+ let score = 0;
216
+ let lives = 3;
217
+ let bricks = [];
218
+ let bullets = [];
219
+ let attackerX = canvas.width / 2;
220
+ let attackerWidth = 50;
221
+ let gunAngle = 0;
222
+ let mouseX = 0;
223
+ let mouseY = 0;
224
+ let animationId;
225
+ let brickSpeed = 2;
226
+ let brickSpawnRate = 60;
227
+ let frameCount = 0;
228
+
229
+ // Attacker element (for visual representation)
230
+ const attacker = document.createElement('div');
231
+ attacker.id = 'attacker';
232
+ document.querySelector('.game-container').appendChild(attacker);
233
+
234
+ const gun = document.createElement('div');
235
+ gun.id = 'gun';
236
+ attacker.appendChild(gun);
237
+
238
+ const gunBarrel = document.createElement('div');
239
+ gunBarrel.id = 'gun-barrel';
240
+ gun.appendChild(gunBarrel);
241
+
242
+ // Event listeners
243
+ startButton.addEventListener('click', startGame);
244
+ restartButton.addEventListener('click', startGame);
245
+
246
+ canvas.addEventListener('mousemove', (e) => {
247
+ const rect = canvas.getBoundingClientRect();
248
+ mouseX = e.clientX - rect.left;
249
+ mouseY = e.clientY - rect.top;
250
 
251
+ // Calculate gun angle based on mouse position
252
+ const dx = mouseX - (attackerX + attackerWidth / 2);
253
+ const dy = mouseY - (canvas.height - 90);
254
+ gunAngle = Math.atan2(dy, dx);
 
255
 
256
+ // Update gun position and rotation
257
+ gun.style.transform = `rotate(${gunAngle}rad)`;
258
+ });
259
+
260
+ canvas.addEventListener('click', shoot);
261
+
262
+ document.addEventListener('keydown', (e) => {
263
+ if (!gameRunning) return;
 
264
 
265
+ if (e.key === 'ArrowLeft') {
266
+ attackerX = Math.max(0, attackerX - 20);
267
+ } else if (e.key === 'ArrowRight') {
268
+ attackerX = Math.min(canvas.width - attackerWidth, attackerX + 20);
269
+ }
270
+ });
271
+
272
+ // Game functions
273
+ function startGame() {
274
+ gameRunning = true;
275
+ score = 0;
276
+ lives = 3;
277
+ bricks = [];
278
+ bullets = [];
279
+ brickSpeed = 2;
280
+ brickSpawnRate = 60;
281
+ frameCount = 0;
282
 
283
+ scoreElement.textContent = score;
284
+ updateLives();
 
 
 
 
 
 
 
 
285
 
286
+ startScreen.classList.add('hidden');
287
+ gameOverScreen.classList.add('hidden');
288
 
289
+ // Reset attacker position
290
+ attackerX = canvas.width / 2 - attackerWidth / 2;
 
 
 
 
 
 
 
 
291
 
292
+ // Start game loop
293
+ animationId = requestAnimationFrame(gameLoop);
294
+ }
295
+
296
+ function gameLoop() {
297
+ if (!gameRunning) return;
 
 
298
 
299
+ // Clear canvas
300
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
 
 
 
 
 
 
301
 
302
+ // Update attacker position
303
+ attacker.style.left = `${attackerX}px`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
+ // Spawn bricks
306
+ if (frameCount % brickSpawnRate === 0) {
307
+ spawnBrick();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
 
310
+ // Update bricks
311
+ updateBricks();
 
 
 
 
 
 
 
 
 
312
 
313
+ // Update bullets
314
+ updateBullets();
 
 
 
 
 
 
 
 
 
315
 
316
+ // Check collisions
317
+ checkCollisions();
318
+
319
+ // Increase difficulty
320
+ if (frameCount % 500 === 0) {
321
+ brickSpeed = Math.min(brickSpeed + 0.2, 6);
322
+ brickSpawnRate = Math.max(brickSpawnRate - 5, 20);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  }
324
 
325
+ frameCount++;
326
+ animationId = requestAnimationFrame(gameLoop);
327
+ }
328
+
329
+ function spawnBrick() {
330
+ const width = Math.random() * 60 + 40;
331
+ const x = Math.random() * (canvas.width - width);
332
+ const color = getRandomColor();
333
 
334
+ // 10% chance for special brick
335
+ const isSpecial = Math.random() < 0.1;
 
 
 
 
 
336
 
337
+ bricks.push({
338
+ x,
339
+ y: 0,
340
+ width,
341
+ height: 20,
342
+ color,
343
+ isSpecial,
344
+ health: isSpecial ? 3 : 1
345
  });
346
+ }
347
+
348
+ function getRandomColor() {
349
+ const colors = [
350
+ '#f56565', // red
351
+ '#48bb78', // green
352
+ '#4299e1', // blue
353
+ '#ed8936', // orange
354
+ '#9f7aea', // purple
355
+ '#ecc94b' // yellow
356
+ ];
357
+ return colors[Math.floor(Math.random() * colors.length)];
358
+ }
359
+
360
+ function updateBricks() {
361
+ for (let i = bricks.length - 1; i >= 0; i--) {
362
+ const brick = bricks[i];
363
 
364
+ // Move brick down
365
+ brick.y += brickSpeed;
366
+
367
+ // Draw brick
368
+ ctx.fillStyle = brick.color;
369
+ ctx.fillRect(brick.x, brick.y, brick.width, brick.height);
 
 
 
 
370
 
371
+ // Draw special effects
372
+ if (brick.isSpecial) {
373
+ ctx.strokeStyle = '#ffffff';
374
+ ctx.lineWidth = 2;
375
+ ctx.strokeRect(brick.x, brick.y, brick.width, brick.height);
376
+
377
+ // Draw health indicator
378
+ ctx.fillStyle = '#ffffff';
379
+ ctx.font = '10px Arial';
380
+ ctx.fillText('★'.repeat(brick.health), brick.x + 5, brick.y + 15);
381
  }
382
+
383
+ // Remove bricks that go off screen
384
+ if (brick.y > canvas.height) {
385
+ bricks.splice(i, 1);
386
+ loseLife();
 
 
 
387
  }
388
  }
389
+ }
390
+
391
+ function updateBullets() {
392
+ for (let i = bullets.length - 1; i >= 0; i--) {
393
+ const bullet = bullets[i];
394
+
395
+ // Move bullet
396
+ bullet.x += bullet.dx * 10;
397
+ bullet.y += bullet.dy * 10;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
 
399
+ // Draw bullet
400
+ const bulletElement = document.createElement('div');
401
+ bulletElement.className = 'bullet';
402
+ bulletElement.style.left = `${bullet.x}px`;
403
+ bulletElement.style.top = `${bullet.y}px`;
404
+ document.querySelector('.game-container').appendChild(bulletElement);
405
 
406
+ // Remove bullet after a short delay to allow animation
407
+ setTimeout(() => {
408
+ if (bulletElement.parentNode) {
409
+ bulletElement.parentNode.removeChild(bulletElement);
410
+ }
411
+ }, 16);
412
 
413
+ // Remove bullets that go off screen
414
+ if (bullet.x < 0 || bullet.x > canvas.width ||
415
+ bullet.y < 0 || bullet.y > canvas.height) {
416
+ bullets.splice(i, 1);
417
+ }
418
  }
419
+ }
420
+
421
+ function checkCollisions() {
422
+ for (let i = bullets.length - 1; i >= 0; i--) {
423
+ const bullet = bullets[i];
424
+
425
+ for (let j = bricks.length - 1; j >= 0; j--) {
426
+ const brick = bricks[j];
427
+
428
+ if (bullet.x > brick.x && bullet.x < brick.x + brick.width &&
429
+ bullet.y > brick.y && bullet.y < brick.y + brick.height) {
430
+
431
+ // Hit brick
432
+ brick.health--;
433
+
434
+ if (brick.health <= 0) {
435
+ // Brick destroyed
436
+ bricks.splice(j, 1);
437
+ score += brick.isSpecial ? 5 : 1;
438
+ scoreElement.textContent = score;
439
+ }
440
+
441
+ // Remove bullet
442
+ bullets.splice(i, 1);
443
+ break;
444
+ }
445
+ }
446
  }
447
+ }
448
+
449
+ function shoot() {
450
+ if (!gameRunning) return;
451
 
452
+ const startX = attackerX + attackerWidth / 2;
453
+ const startY = canvas.height - 90;
 
 
454
 
455
+ bullets.push({
456
+ x: startX,
457
+ y: startY,
458
+ dx: Math.cos(gunAngle),
459
+ dy: Math.sin(gunAngle)
460
+ });
461
+ }
462
+
463
+ function loseLife() {
464
+ lives--;
465
+ updateLives();
466
 
467
+ if (lives <= 0) {
468
+ gameOver();
469
+ }
470
+ }
471
+
472
+ function updateLives() {
473
+ livesElement.innerHTML = '';
474
+ for (let i = 0; i < lives; i++) {
475
+ const heart = document.createElement('i');
476
+ heart.className = 'fas fa-heart heart-icon';
477
+ livesElement.appendChild(heart);
 
 
 
 
 
 
 
 
 
478
  }
479
+ }
480
+
481
+ function gameOver() {
482
+ gameRunning = false;
483
+ cancelAnimationFrame(animationId);
484
 
485
+ finalScoreElement.textContent = score;
486
+ gameOverScreen.classList.remove('hidden');
487
+ }
488
  </script>
489
  <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=Mohabedalgani/zaido" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
490
  </html>