nkp2mr commited on
Commit
a0bb411
·
verified ·
1 Parent(s): 789d9f8

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +574 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Test
3
- emoji: 📈
4
  colorFrom: yellow
5
- colorTo: green
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: test
3
+ emoji: 🐳
4
  colorFrom: yellow
5
+ colorTo: purple
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,574 @@
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>Breakout Game | 打砖块</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
10
+
11
+ body {
12
+ font-family: 'Press Start 2P', cursive;
13
+ overflow: hidden;
14
+ background: linear-gradient(135deg, #1a1a2e, #16213e);
15
+ }
16
+
17
+ #gameCanvas {
18
+ box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
19
+ border-radius: 8px;
20
+ }
21
+
22
+ .brick {
23
+ transition: all 0.2s ease;
24
+ }
25
+
26
+ .brick:hover {
27
+ transform: scale(1.05);
28
+ }
29
+
30
+ .power-up {
31
+ animation: float 2s ease-in-out infinite;
32
+ }
33
+
34
+ @keyframes float {
35
+ 0%, 100% { transform: translateY(0); }
36
+ 50% { transform: translateY(-5px); }
37
+ }
38
+
39
+ .game-over {
40
+ animation: pulse 1.5s infinite;
41
+ }
42
+
43
+ @keyframes pulse {
44
+ 0% { transform: scale(1); }
45
+ 50% { transform: scale(1.05); }
46
+ 100% { transform: scale(1); }
47
+ }
48
+ </style>
49
+ </head>
50
+ <body class="min-h-screen flex flex-col items-center justify-center text-white">
51
+ <div class="text-center mb-6">
52
+ <h1 class="text-4xl md:text-5xl mb-4 text-cyan-400">BREAKOUT</h1>
53
+ <h2 class="text-xl md:text-2xl text-cyan-300">打砖块游戏</h2>
54
+ </div>
55
+
56
+ <div class="relative">
57
+ <canvas id="gameCanvas" width="800" height="500" class="bg-gray-900"></canvas>
58
+
59
+ <!-- Start Screen -->
60
+ <div id="startScreen" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-80 p-8 rounded-lg">
61
+ <h3 class="text-3xl text-cyan-400 mb-6">BREAKOUT</h3>
62
+ <p class="text-lg mb-8 text-center">Use mouse or arrow keys to move the paddle.<br>Break all bricks to win!</p>
63
+ <button id="startButton" class="px-8 py-3 bg-cyan-600 hover:bg-cyan-500 rounded-lg text-lg font-bold transition-all transform hover:scale-105">
64
+ START GAME
65
+ </button>
66
+ <div class="mt-6 text-sm text-gray-400">
67
+ <p>Controls: ← → or Mouse</p>
68
+ <p class="mt-2">Press P to pause</p>
69
+ </div>
70
+ </div>
71
+
72
+ <!-- Game Over Screen -->
73
+ <div id="gameOverScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80 p-8 rounded-lg">
74
+ <h3 class="text-3xl text-red-500 mb-4 game-over">GAME OVER</h3>
75
+ <p id="finalScore" class="text-xl mb-6">Score: 0</p>
76
+ <button id="restartButton" class="px-8 py-3 bg-cyan-600 hover:bg-cyan-500 rounded-lg text-lg font-bold transition-all transform hover:scale-105">
77
+ PLAY AGAIN
78
+ </button>
79
+ </div>
80
+
81
+ <!-- Win Screen -->
82
+ <div id="winScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80 p-8 rounded-lg">
83
+ <h3 class="text-3xl text-green-400 mb-4">YOU WIN!</h3>
84
+ <p id="winScore" class="text-xl mb-6">Score: 0</p>
85
+ <button id="nextLevelButton" class="px-8 py-3 bg-green-600 hover:bg-green-500 rounded-lg text-lg font-bold transition-all transform hover:scale-105 mb-4">
86
+ NEXT LEVEL
87
+ </button>
88
+ <button id="menuButton" class="px-8 py-3 bg-cyan-600 hover:bg-cyan-500 rounded-lg text-lg font-bold transition-all transform hover:scale-105">
89
+ MAIN MENU
90
+ </button>
91
+ </div>
92
+
93
+ <!-- Pause Screen -->
94
+ <div id="pauseScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80 p-8 rounded-lg">
95
+ <h3 class="text-3xl text-yellow-400 mb-6">PAUSED</h3>
96
+ <button id="resumeButton" class="px-8 py-3 bg-cyan-600 hover:bg-cyan-500 rounded-lg text-lg font-bold transition-all transform hover:scale-105">
97
+ RESUME
98
+ </button>
99
+ </div>
100
+ </div>
101
+
102
+ <div class="mt-6 flex justify-between w-full max-w-2xl px-4">
103
+ <div class="bg-gray-800 bg-opacity-70 px-6 py-3 rounded-lg">
104
+ <span class="text-gray-400">Level:</span>
105
+ <span id="levelDisplay" class="ml-2 text-yellow-400">1</span>
106
+ </div>
107
+ <div class="bg-gray-800 bg-opacity-70 px-6 py-3 rounded-lg">
108
+ <span class="text-gray-400">Score:</span>
109
+ <span id="scoreDisplay" class="ml-2 text-green-400">0</span>
110
+ </div>
111
+ <div class="bg-gray-800 bg-opacity-70 px-6 py-3 rounded-lg">
112
+ <span class="text-gray-400">Lives:</span>
113
+ <span id="livesDisplay" class="ml-2 text-red-400">3</span>
114
+ </div>
115
+ </div>
116
+
117
+ <script>
118
+ // Game variables
119
+ const canvas = document.getElementById('gameCanvas');
120
+ const ctx = canvas.getContext('2d');
121
+ const startScreen = document.getElementById('startScreen');
122
+ const gameOverScreen = document.getElementById('gameOverScreen');
123
+ const winScreen = document.getElementById('winScreen');
124
+ const pauseScreen = document.getElementById('pauseScreen');
125
+ const scoreDisplay = document.getElementById('scoreDisplay');
126
+ const livesDisplay = document.getElementById('livesDisplay');
127
+ const levelDisplay = document.getElementById('levelDisplay');
128
+ const finalScore = document.getElementById('finalScore');
129
+ const winScore = document.getElementById('winScore');
130
+
131
+ // Game state
132
+ let gameRunning = false;
133
+ let gamePaused = false;
134
+ let score = 0;
135
+ let lives = 3;
136
+ let level = 1;
137
+
138
+ // Paddle
139
+ const paddleHeight = 15;
140
+ const paddleWidth = 100;
141
+ let paddleX = (canvas.width - paddleWidth) / 2;
142
+
143
+ // Ball
144
+ const ballRadius = 10;
145
+ let ballX = canvas.width / 2;
146
+ let ballY = canvas.height - 30;
147
+ let ballSpeedX = 5;
148
+ let ballSpeedY = -5;
149
+
150
+ // Bricks
151
+ const brickRowCount = 5;
152
+ const brickColumnCount = 9;
153
+ const brickWidth = 75;
154
+ const brickHeight = 20;
155
+ const brickPadding = 10;
156
+ const brickOffsetTop = 60;
157
+ const brickOffsetLeft = 30;
158
+
159
+ let bricks = [];
160
+
161
+ // Power-ups
162
+ const powerUps = [];
163
+ const powerUpTypes = ['extraLife', 'expandPaddle', 'slowBall', 'multiBall'];
164
+
165
+ // Initialize bricks
166
+ function initBricks() {
167
+ bricks = [];
168
+ for (let c = 0; c < brickColumnCount; c++) {
169
+ bricks[c] = [];
170
+ for (let r = 0; r < brickRowCount; r++) {
171
+ const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
172
+ const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
173
+
174
+ // Different colors for different rows
175
+ let color;
176
+ switch(r) {
177
+ case 0: color = '#FF5252'; break;
178
+ case 1: color = '#FFD740'; break;
179
+ case 2: color = '#69F0AE'; break;
180
+ case 3: color = '#40C4FF'; break;
181
+ case 4: color = '#E040FB'; break;
182
+ }
183
+
184
+ // Higher rows give more points
185
+ const points = (brickRowCount - r) * 10;
186
+
187
+ // Some bricks are unbreakable
188
+ const unbreakable = Math.random() < 0.1 && r === 0;
189
+
190
+ bricks[c][r] = { x: brickX, y: brickY, width: brickWidth, height: brickHeight,
191
+ color: color, visible: true, points: points, unbreakable: unbreakable };
192
+ }
193
+ }
194
+ }
195
+
196
+ // Event listeners
197
+ document.addEventListener('keydown', keyDownHandler);
198
+ document.addEventListener('keyup', keyUpHandler);
199
+ document.addEventListener('mousemove', mouseMoveHandler);
200
+
201
+ document.getElementById('startButton').addEventListener('click', startGame);
202
+ document.getElementById('restartButton').addEventListener('click', startGame);
203
+ document.getElementById('nextLevelButton').addEventListener('click', nextLevel);
204
+ document.getElementById('menuButton').addEventListener('click', showMenu);
205
+ document.getElementById('resumeButton').addEventListener('click', togglePause);
206
+
207
+ // Keyboard controls
208
+ let rightPressed = false;
209
+ let leftPressed = false;
210
+
211
+ function keyDownHandler(e) {
212
+ if (e.key === 'Right' || e.key === 'ArrowRight') {
213
+ rightPressed = true;
214
+ } else if (e.key === 'Left' || e.key === 'ArrowLeft') {
215
+ leftPressed = true;
216
+ } else if (e.key === 'p' || e.key === 'P') {
217
+ togglePause();
218
+ }
219
+ }
220
+
221
+ function keyUpHandler(e) {
222
+ if (e.key === 'Right' || e.key === 'ArrowRight') {
223
+ rightPressed = false;
224
+ } else if (e.key === 'Left' || e.key === 'ArrowLeft') {
225
+ leftPressed = false;
226
+ }
227
+ }
228
+
229
+ // Mouse controls
230
+ function mouseMoveHandler(e) {
231
+ if (!gameRunning || gamePaused) return;
232
+
233
+ const relativeX = e.clientX - canvas.offsetLeft;
234
+ if (relativeX > 0 && relativeX < canvas.width) {
235
+ paddleX = relativeX - paddleWidth / 2;
236
+
237
+ // Keep paddle within canvas
238
+ if (paddleX < 0) {
239
+ paddleX = 0;
240
+ } else if (paddleX + paddleWidth > canvas.width) {
241
+ paddleX = canvas.width - paddleWidth;
242
+ }
243
+ }
244
+ }
245
+
246
+ // Collision detection
247
+ function collisionDetection() {
248
+ for (let c = 0; c < brickColumnCount; c++) {
249
+ for (let r = 0; r < brickRowCount; r++) {
250
+ const brick = bricks[c][r];
251
+ if (brick.visible && !brick.unbreakable) {
252
+ if (ballX > brick.x && ballX < brick.x + brickWidth &&
253
+ ballY > brick.y && ballY < brick.y + brickHeight) {
254
+
255
+ ballSpeedY = -ballSpeedY;
256
+ brick.visible = false;
257
+ score += brick.points;
258
+ scoreDisplay.textContent = score;
259
+
260
+ // Chance to drop power-up
261
+ if (Math.random() < 0.2) {
262
+ spawnPowerUp(brick.x + brickWidth / 2, brick.y + brickHeight / 2);
263
+ }
264
+
265
+ // Check if all bricks are destroyed
266
+ if (checkWin()) {
267
+ showWinScreen();
268
+ }
269
+ }
270
+ }
271
+ }
272
+ }
273
+ }
274
+
275
+ // Power-up functions
276
+ function spawnPowerUp(x, y) {
277
+ const type = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)];
278
+ powerUps.push({
279
+ x: x,
280
+ y: y,
281
+ width: 20,
282
+ height: 20,
283
+ type: type,
284
+ speed: 2,
285
+ active: false
286
+ });
287
+ }
288
+
289
+ function activatePowerUp(powerUp) {
290
+ switch(powerUp.type) {
291
+ case 'extraLife':
292
+ lives++;
293
+ livesDisplay.textContent = lives;
294
+ break;
295
+ case 'expandPaddle':
296
+ paddleWidth = 150;
297
+ setTimeout(() => { paddleWidth = 100; }, 10000);
298
+ break;
299
+ case 'slowBall':
300
+ ballSpeedX *= 0.7;
301
+ ballSpeedY *= 0.7;
302
+ setTimeout(() => {
303
+ ballSpeedX /= 0.7;
304
+ ballSpeedY /= 0.7;
305
+ }, 8000);
306
+ break;
307
+ case 'multiBall':
308
+ // For simplicity, we'll just add score here
309
+ score += 50;
310
+ scoreDisplay.textContent = score;
311
+ break;
312
+ }
313
+ }
314
+
315
+ // Check if player won
316
+ function checkWin() {
317
+ for (let c = 0; c < brickColumnCount; c++) {
318
+ for (let r = 0; r < brickRowCount; r++) {
319
+ if (bricks[c][r].visible && !bricks[c][r].unbreakable) {
320
+ return false;
321
+ }
322
+ }
323
+ }
324
+ return true;
325
+ }
326
+
327
+ // Draw functions
328
+ function drawBall() {
329
+ ctx.beginPath();
330
+ ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
331
+ ctx.fillStyle = '#FFFFFF';
332
+ ctx.fill();
333
+ ctx.closePath();
334
+ }
335
+
336
+ function drawPaddle() {
337
+ ctx.beginPath();
338
+ ctx.roundRect(paddleX, canvas.height - paddleHeight - 10, paddleWidth, paddleHeight, 10);
339
+ ctx.fillStyle = '#40C4FF';
340
+ ctx.fill();
341
+ ctx.closePath();
342
+ }
343
+
344
+ function drawBricks() {
345
+ for (let c = 0; c < brickColumnCount; c++) {
346
+ for (let r = 0; r < brickRowCount; r++) {
347
+ if (bricks[c][r].visible) {
348
+ ctx.beginPath();
349
+ ctx.roundRect(bricks[c][r].x, bricks[c][r].y, brickWidth, brickHeight, 4);
350
+ ctx.fillStyle = bricks[c][r].unbreakable ? '#555555' : bricks[c][r].color;
351
+ ctx.fill();
352
+ ctx.strokeStyle = '#000000';
353
+ ctx.stroke();
354
+ ctx.closePath();
355
+
356
+ // Draw crack pattern for unbreakable bricks
357
+ if (bricks[c][r].unbreakable) {
358
+ ctx.beginPath();
359
+ ctx.moveTo(bricks[c][r].x + 5, bricks[c][r].y + 5);
360
+ ctx.lineTo(bricks[c][r].x + brickWidth - 5, bricks[c][r].y + brickHeight - 5);
361
+ ctx.moveTo(bricks[c][r].x + brickWidth - 5, bricks[c][r].y + 5);
362
+ ctx.lineTo(bricks[c][r].x + 5, bricks[c][r].y + brickHeight - 5);
363
+ ctx.strokeStyle = '#333333';
364
+ ctx.lineWidth = 2;
365
+ ctx.stroke();
366
+ ctx.closePath();
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+
373
+ function drawPowerUps() {
374
+ powerUps.forEach(powerUp => {
375
+ if (!powerUp.active) {
376
+ ctx.beginPath();
377
+ ctx.roundRect(powerUp.x - powerUp.width / 2, powerUp.y - powerUp.height / 2,
378
+ powerUp.width, powerUp.height, 4);
379
+
380
+ // Different colors for different power-ups
381
+ switch(powerUp.type) {
382
+ case 'extraLife': ctx.fillStyle = '#FF5252'; break;
383
+ case 'expandPaddle': ctx.fillStyle = '#69F0AE'; break;
384
+ case 'slowBall': ctx.fillStyle = '#40C4FF'; break;
385
+ case 'multiBall': ctx.fillStyle = '#E040FB'; break;
386
+ }
387
+
388
+ ctx.fill();
389
+ ctx.strokeStyle = '#FFFFFF';
390
+ ctx.stroke();
391
+ ctx.closePath();
392
+
393
+ // Draw icon
394
+ ctx.font = '12px Arial';
395
+ ctx.fillStyle = '#FFFFFF';
396
+ ctx.textAlign = 'center';
397
+ ctx.textBaseline = 'middle';
398
+
399
+ let symbol = '';
400
+ switch(powerUp.type) {
401
+ case 'extraLife': symbol = '♥'; break;
402
+ case 'expandPaddle': symbol = '⇆'; break;
403
+ case 'slowBall': symbol = '⏱'; break;
404
+ case 'multiBall': symbol = '✦'; break;
405
+ }
406
+
407
+ ctx.fillText(symbol, powerUp.x, powerUp.y);
408
+ }
409
+ });
410
+ }
411
+
412
+ // Game control functions
413
+ function startGame() {
414
+ gameRunning = true;
415
+ gamePaused = false;
416
+ score = 0;
417
+ lives = 3;
418
+ level = 1;
419
+
420
+ scoreDisplay.textContent = score;
421
+ livesDisplay.textContent = lives;
422
+ levelDisplay.textContent = level;
423
+
424
+ initBricks();
425
+ resetBall();
426
+
427
+ startScreen.classList.add('hidden');
428
+ gameOverScreen.classList.add('hidden');
429
+ winScreen.classList.add('hidden');
430
+ pauseScreen.classList.add('hidden');
431
+
432
+ requestAnimationFrame(gameLoop);
433
+ }
434
+
435
+ function nextLevel() {
436
+ level++;
437
+ levelDisplay.textContent = level;
438
+
439
+ // Increase difficulty
440
+ ballSpeedX *= 1.1;
441
+ ballSpeedY *= 1.1;
442
+
443
+ initBricks();
444
+ resetBall();
445
+
446
+ winScreen.classList.add('hidden');
447
+ requestAnimationFrame(gameLoop);
448
+ }
449
+
450
+ function showMenu() {
451
+ winScreen.classList.add('hidden');
452
+ startScreen.classList.remove('hidden');
453
+ }
454
+
455
+ function togglePause() {
456
+ if (!gameRunning) return;
457
+
458
+ gamePaused = !gamePaused;
459
+
460
+ if (gamePaused) {
461
+ pauseScreen.classList.remove('hidden');
462
+ } else {
463
+ pauseScreen.classList.add('hidden');
464
+ requestAnimationFrame(gameLoop);
465
+ }
466
+ }
467
+
468
+ function showGameOver() {
469
+ gameRunning = false;
470
+ finalScore.textContent = `Score: ${score}`;
471
+ gameOverScreen.classList.remove('hidden');
472
+ }
473
+
474
+ function showWinScreen() {
475
+ gameRunning = false;
476
+ winScore.textContent = `Score: ${score}`;
477
+ winScreen.classList.remove('hidden');
478
+ }
479
+
480
+ function resetBall() {
481
+ ballX = canvas.width / 2;
482
+ ballY = canvas.height - 30;
483
+ ballSpeedX = 5 * (Math.random() > 0.5 ? 1 : -1);
484
+ ballSpeedY = -5;
485
+ paddleX = (canvas.width - paddleWidth) / 2;
486
+ }
487
+
488
+ // Main game loop
489
+ function gameLoop() {
490
+ if (!gameRunning || gamePaused) return;
491
+
492
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
493
+
494
+ // Draw game elements
495
+ drawBricks();
496
+ drawBall();
497
+ drawPaddle();
498
+ drawPowerUps();
499
+
500
+ // Collision detection
501
+ collisionDetection();
502
+
503
+ // Ball movement
504
+ ballX += ballSpeedX;
505
+ ballY += ballSpeedY;
506
+
507
+ // Wall collision
508
+ if (ballX + ballSpeedX > canvas.width - ballRadius || ballX + ballSpeedX < ballRadius) {
509
+ ballSpeedX = -ballSpeedX;
510
+ }
511
+
512
+ if (ballY + ballSpeedY < ballRadius) {
513
+ ballSpeedY = -ballSpeedY;
514
+ } else if (ballY + ballSpeedY > canvas.height - ballRadius) {
515
+ // Paddle collision
516
+ if (ballX > paddleX && ballX < paddleX + paddleWidth) {
517
+ // Calculate bounce angle based on where ball hits paddle
518
+ const hitPosition = (ballX - (paddleX + paddleWidth / 2)) / (paddleWidth / 2);
519
+ const angle = hitPosition * Math.PI / 3; // Max 60 degrees
520
+
521
+ ballSpeedX = 5 * Math.sin(angle);
522
+ ballSpeedY = -5 * Math.cos(angle);
523
+ } else {
524
+ // Missed paddle
525
+ lives--;
526
+ livesDisplay.textContent = lives;
527
+
528
+ if (lives <= 0) {
529
+ showGameOver();
530
+ } else {
531
+ resetBall();
532
+ }
533
+ }
534
+ }
535
+
536
+ // Paddle movement
537
+ if (rightPressed && paddleX < canvas.width - paddleWidth) {
538
+ paddleX += 7;
539
+ } else if (leftPressed && paddleX > 0) {
540
+ paddleX -= 7;
541
+ }
542
+
543
+ // Power-up movement and collision
544
+ for (let i = powerUps.length - 1; i >= 0; i--) {
545
+ const powerUp = powerUps[i];
546
+
547
+ if (!powerUp.active) {
548
+ powerUp.y += powerUp.speed;
549
+
550
+ // Check if power-up hits paddle
551
+ if (powerUp.y + powerUp.height / 2 > canvas.height - paddleHeight - 10 &&
552
+ powerUp.y - powerUp.height / 2 < canvas.height - 10 &&
553
+ powerUp.x + powerUp.width / 2 > paddleX &&
554
+ powerUp.x - powerUp.width / 2 < paddleX + paddleWidth) {
555
+
556
+ activatePowerUp(powerUp);
557
+ powerUps.splice(i, 1);
558
+ }
559
+
560
+ // Check if power-up falls off screen
561
+ if (powerUp.y > canvas.height) {
562
+ powerUps.splice(i, 1);
563
+ }
564
+ }
565
+ }
566
+
567
+ requestAnimationFrame(gameLoop);
568
+ }
569
+
570
+ // Initial setup
571
+ initBricks();
572
+ </script>
573
+ <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=nkp2mr/test" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
574
+ </html>