alvesrt commited on
Commit
104e82c
·
verified ·
1 Parent(s): 7f4acfd

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +260 -112
index.html CHANGED
@@ -11,21 +11,32 @@
11
  50% { clip-path: polygon(50% 50%, 100% 40%, 100% 60%); }
12
  100% { clip-path: polygon(50% 50%, 100% 0%, 100% 100%); }
13
  }
14
-
15
  @keyframes ghost-movement {
16
  0% { transform: translateY(0); }
17
  50% { transform: translateY(-5px); }
18
  100% { transform: translateY(0); }
19
  }
20
-
 
 
 
 
 
 
 
 
 
 
 
21
  .pacman {
22
  animation: pacman-mouth 0.5s infinite;
23
  }
24
-
25
  .ghost {
26
  animation: ghost-movement 1s infinite;
27
  }
28
-
29
  .ghost::before {
30
  content: '';
31
  position: absolute;
@@ -36,7 +47,7 @@
36
  top: -10px;
37
  left: 10px;
38
  }
39
-
40
  .ghost::after {
41
  content: '';
42
  position: absolute;
@@ -48,7 +59,7 @@
48
  left: 15px;
49
  box-shadow: 10px 0 black;
50
  }
51
-
52
  .ghost-eye {
53
  width: 6px;
54
  height: 6px;
@@ -58,7 +69,7 @@
58
  top: -3px;
59
  left: 13px;
60
  }
61
-
62
  .ghost-pupil {
63
  width: 2px;
64
  height: 2px;
@@ -68,12 +79,12 @@
68
  top: 1px;
69
  left: 1px;
70
  }
71
-
72
  .wall {
73
  background-color: #2563eb;
74
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
75
  }
76
-
77
  .dot {
78
  width: 6px;
79
  height: 6px;
@@ -81,7 +92,7 @@
81
  border-radius: 50%;
82
  box-shadow: 0 0 5px #fbbf24;
83
  }
84
-
85
  .power-pellet {
86
  width: 12px;
87
  height: 12px;
@@ -90,13 +101,15 @@
90
  box-shadow: 0 0 10px #fbbf24;
91
  animation: pulse 1s infinite;
92
  }
93
-
94
- @keyframes pulse {
95
- 0% { transform: scale(1); }
96
- 50% { transform: scale(1.2); }
97
- 100% { transform: scale(1); }
 
 
98
  }
99
-
100
  #game-board {
101
  position: relative;
102
  width: 560px;
@@ -104,43 +117,65 @@
104
  border: 2px solid #1e40af;
105
  background-color: #1e1b4b;
106
  }
107
-
108
  .cell {
109
  width: 20px;
110
  height: 20px;
111
  position: absolute;
112
  }
113
-
114
  #score-display {
115
  font-family: 'Courier New', monospace;
116
  letter-spacing: 2px;
117
  }
118
-
119
- #game-over {
120
  background-color: rgba(0, 0, 0, 0.8);
121
  z-index: 100;
122
  }
 
 
 
 
 
 
 
 
 
 
 
 
123
  </style>
124
  </head>
125
  <body class="bg-gray-900 min-h-screen flex flex-col items-center justify-center p-4">
126
- <div class="text-center mb-4">
 
 
 
 
 
 
 
 
 
 
 
 
127
  <h1 class="text-4xl font-bold text-yellow-400 mb-2">PAC-MAN</h1>
128
  <div id="score-display" class="text-2xl font-mono text-white">
129
  SCORE: <span id="score">0</span>
130
  </div>
131
  </div>
132
-
133
- <div id="game-board" class="relative">
134
- <!-- Game elements will be added here by JavaScript -->
135
- </div>
136
-
137
- <div class="mt-4 text-white">
138
  <p class="mb-2">Use arrow keys to move Pac-Man</p>
139
  <button id="restart-btn" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded hidden">
140
  Play Again
141
  </button>
142
  </div>
143
-
144
  <div id="game-over" class="absolute hidden flex-col items-center justify-center text-white">
145
  <h2 class="text-4xl font-bold text-red-500 mb-4">GAME OVER</h2>
146
  <p class="text-2xl mb-4">Final Score: <span id="final-score">0</span></p>
@@ -148,7 +183,7 @@
148
  Play Again
149
  </button>
150
  </div>
151
-
152
  <script>
153
  document.addEventListener('DOMContentLoaded', () => {
154
  // Game constants
@@ -157,9 +192,11 @@
157
  const COLS = 28;
158
  const BOARD_WIDTH = COLS * CELL_SIZE;
159
  const BOARD_HEIGHT = ROWS * CELL_SIZE;
160
-
 
161
  // Game state
162
  let score = 0;
 
163
  let pacman = { x: 14, y: 23, direction: 'right', nextDirection: 'right' };
164
  let ghosts = [];
165
  let dots = [];
@@ -168,8 +205,11 @@
168
  let gameRunning = false;
169
  let scaredGhosts = false;
170
  let scaredTimer = null;
171
- let lives = 3;
172
-
 
 
 
173
  // Maze layout (1 = wall, 0 = path, . = dot, o = power pellet)
174
  const layout = [
175
  '1111111111111111111111111111',
@@ -183,17 +223,17 @@
183
  '1......111....11....111....1',
184
  '111111.111111.111111.111111',
185
  '111111.111111.111111.111111',
186
- '111111.111 111.1111',
187
  '111111.111 111111 111.1111',
188
- '111111.111 1 1 111.1111',
189
- '1............1 1......1',
190
  '1.1111.11111 111111 111.11',
191
- '1.1111.11111 111.11',
192
  '1.1111.11111 111111 111.111',
193
- '1......11111 1 1 111....1',
194
- '111111.11111 1 1 111.1111',
195
  '111111.11111 111111 111.1111',
196
- '111111.11111 111.1111',
197
  '1............111111......1',
198
  '1.1111.11111.111.11111.1111',
199
  '1.1111.11111.111.11111.1111',
@@ -205,7 +245,7 @@
205
  '1..........................1',
206
  '1111111111111111111111111111'
207
  ];
208
-
209
  // Initialize game
210
  function initGame() {
211
  score = 0;
@@ -213,14 +253,21 @@
213
  document.getElementById('score').textContent = score;
214
  document.getElementById('game-over').classList.add('hidden');
215
  document.getElementById('restart-btn').classList.add('hidden');
216
-
 
 
 
 
 
217
  // Clear previous game elements
218
  document.getElementById('game-board').innerHTML = '';
219
  dots = [];
220
  powerPellets = [];
221
  walls = [];
222
  ghosts = [];
223
-
 
 
224
  // Create game elements based on layout
225
  for (let y = 0; y < ROWS; y++) {
226
  for (let x = 0; x < COLS; x++) {
@@ -229,7 +276,7 @@
229
  cellElement.className = 'cell';
230
  cellElement.style.left = `${x * CELL_SIZE}px`;
231
  cellElement.style.top = `${y * CELL_SIZE}px`;
232
-
233
  if (cell === '1') {
234
  // Wall
235
  cellElement.classList.add('wall');
@@ -253,7 +300,7 @@
253
  }
254
  }
255
  }
256
-
257
  // Create Pac-Man
258
  const pacmanElement = document.createElement('div');
259
  pacmanElement.id = 'pacman';
@@ -261,17 +308,18 @@
261
  pacmanElement.style.left = `${pacman.x * CELL_SIZE}px`;
262
  pacmanElement.style.top = `${pacman.y * CELL_SIZE}px`;
263
  document.getElementById('game-board').appendChild(pacmanElement);
264
-
265
  // Create ghosts
266
  createGhost('blinky', 13, 11, 'red');
267
  createGhost('pinky', 14, 11, 'pink');
268
  createGhost('inky', 13, 14, 'cyan');
269
  createGhost('clyde', 14, 14, 'orange');
270
-
271
  gameRunning = true;
272
  requestAnimationFrame(gameLoop);
 
273
  }
274
-
275
  function createGhost(id, x, y, color) {
276
  const ghost = {
277
  id,
@@ -282,114 +330,114 @@
282
  isScared: false,
283
  isEaten: false
284
  };
285
-
286
  const ghostElement = document.createElement('div');
287
  ghostElement.id = id;
288
  ghostElement.className = `ghost absolute w-5 h-5 bg-${color}-500 rounded-t-full`;
289
  ghostElement.style.left = `${x * CELL_SIZE}px`;
290
  ghostElement.style.top = `${y * CELL_SIZE}px`;
291
-
292
  // Add eyes
293
  const leftEye = document.createElement('div');
294
  leftEye.className = 'ghost-eye';
295
  leftEye.style.left = '8px';
296
-
297
  const rightEye = document.createElement('div');
298
  rightEye.className = 'ghost-eye';
299
  rightEye.style.left = '18px';
300
-
301
  const leftPupil = document.createElement('div');
302
  leftPupil.className = 'ghost-pupil';
303
-
304
  const rightPupil = document.createElement('div');
305
  rightPupil.className = 'ghost-pupil';
306
-
307
  leftEye.appendChild(leftPupil);
308
  rightEye.appendChild(rightPupil);
309
  ghostElement.appendChild(leftEye);
310
  ghostElement.appendChild(rightEye);
311
-
312
  document.getElementById('game-board').appendChild(ghostElement);
313
  ghost.element = ghostElement;
314
  ghosts.push(ghost);
315
-
316
  return ghost;
317
  }
318
-
319
  // Game loop
320
  function gameLoop(timestamp) {
321
  if (!gameRunning) return;
322
-
323
  movePacman();
324
  moveGhosts();
325
  checkCollisions();
326
  updateDisplay();
327
-
328
  if (dots.length === 0 && powerPellets.length === 0) {
329
- // All dots eaten - level complete
330
  gameRunning = false;
331
  setTimeout(() => {
332
- alert('Level Complete! Final Score: ' + score);
333
  initGame();
334
  }, 500);
335
  return;
336
  }
337
-
338
  requestAnimationFrame(gameLoop);
339
  }
340
-
341
  // Move Pac-Man
342
  function movePacman() {
343
  const pacmanElement = document.getElementById('pacman');
344
-
345
  // Try to change direction if there's a next direction queued
346
  if (pacman.nextDirection !== pacman.direction) {
347
  const nextX = Math.round(pacman.x);
348
  const nextY = Math.round(pacman.y);
349
-
350
  if (canMove(nextX, nextY, pacman.nextDirection)) {
351
  pacman.direction = pacman.nextDirection;
352
  }
353
  }
354
-
355
  // Calculate new position
356
  let newX = pacman.x;
357
  let newY = pacman.y;
358
-
359
  switch (pacman.direction) {
360
  case 'left':
361
- newX -= 0.1;
362
  pacmanElement.style.transform = 'rotate(180deg)';
363
  break;
364
  case 'right':
365
- newX += 0.1;
366
  pacmanElement.style.transform = 'rotate(0deg)';
367
  break;
368
  case 'up':
369
- newY -= 0.1;
370
  pacmanElement.style.transform = 'rotate(-90deg)';
371
  break;
372
  case 'down':
373
- newY += 0.1;
374
  pacmanElement.style.transform = 'rotate(90deg)';
375
  break;
376
  }
377
-
378
  // Check if new position is valid
379
  if (canMove(Math.floor(newX), Math.floor(newY), pacman.direction)) {
380
  pacman.x = newX;
381
  pacman.y = newY;
382
-
383
  // Handle tunnel/wrap-around
384
  if (pacman.x < 0) pacman.x = COLS - 1;
385
  if (pacman.x >= COLS) pacman.x = 0;
386
-
387
  // Update position
388
  pacmanElement.style.left = `${pacman.x * CELL_SIZE}px`;
389
  pacmanElement.style.top = `${pacman.y * CELL_SIZE}px`;
390
  }
391
  }
392
-
393
  // Move ghosts
394
  function moveGhosts() {
395
  ghosts.forEach(ghost => {
@@ -397,7 +445,7 @@
397
  // Ghost is returning to base
398
  const targetX = 13;
399
  const targetY = 11;
400
-
401
  if (ghost.x < targetX) ghost.direction = 'right';
402
  else if (ghost.x > targetX) ghost.direction = 'left';
403
  else if (ghost.y < targetY) ghost.direction = 'down';
@@ -417,27 +465,27 @@
417
  'left': 'right',
418
  'right': 'left'
419
  };
420
-
421
  // Don't go back the way you came
422
  const possibleDirections = directions.filter(dir => dir !== oppositeDir[ghost.direction]);
423
-
424
  // Filter to only valid moves
425
  const validDirections = possibleDirections.filter(dir => {
426
  const testX = Math.floor(ghost.x);
427
  const testY = Math.floor(ghost.y);
428
  return canMove(testX, testY, dir);
429
  });
430
-
431
  if (validDirections.length > 0) {
432
  // Choose random direction (simple AI)
433
  ghost.direction = validDirections[Math.floor(Math.random() * validDirections.length)];
434
  }
435
  }
436
-
437
  // Move ghost
438
  let newX = ghost.x;
439
  let newY = ghost.y;
440
-
441
  switch (ghost.direction) {
442
  case 'left':
443
  newX -= ghost.speed * 0.05;
@@ -452,47 +500,92 @@
452
  newY += ghost.speed * 0.05;
453
  break;
454
  }
455
-
456
  // Check if new position is valid
457
  if (canMove(Math.floor(newX), Math.floor(newY), ghost.direction)) {
458
  ghost.x = newX;
459
  ghost.y = newY;
460
-
461
  // Handle tunnel/wrap-around
462
  if (ghost.x < 0) ghost.x = COLS - 1;
463
  if (ghost.x >= COLS) ghost.x = 0;
464
-
465
  // Update position
466
  ghost.element.style.left = `${ghost.x * CELL_SIZE}px`;
467
  ghost.element.style.top = `${ghost.y * CELL_SIZE}px`;
468
  }
469
  });
470
  }
471
-
472
  // Check if movement is possible
473
  function canMove(x, y, direction) {
474
  // Check if out of bounds (except for tunnels)
475
  if (y < 0 || y >= ROWS) return false;
476
-
477
  // Check for walls
478
  const nextX = direction === 'left' ? x - 1 : direction === 'right' ? x + 1 : x;
479
  const nextY = direction === 'up' ? y - 1 : direction === 'down' ? y + 1 : y;
480
-
481
  // Allow tunnel wrap-around
482
  if (nextX < 0 || nextX >= COLS) {
483
  return y === 14 && (nextX < 0 || nextX >= COLS);
484
  }
485
-
486
  if (nextY < 0 || nextY >= ROWS) return false;
487
-
488
  return layout[nextY][nextX] !== '1';
489
  }
490
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  // Check for collisions
492
  function checkCollisions() {
493
  const pacmanCellX = Math.round(pacman.x);
494
  const pacmanCellY = Math.round(pacman.y);
495
-
496
  // Check for dot collisions
497
  for (let i = dots.length - 1; i >= 0; i--) {
498
  const dot = dots[i];
@@ -504,7 +597,7 @@
504
  document.getElementById('score').textContent = score;
505
  }
506
  }
507
-
508
  // Check for power pellet collisions
509
  for (let i = powerPellets.length - 1; i >= 0; i--) {
510
  const pellet = powerPellets[i];
@@ -514,7 +607,7 @@
514
  powerPellets.splice(i, 1);
515
  score += 50;
516
  document.getElementById('score').textContent = score;
517
-
518
  // Make ghosts scared
519
  scaredGhosts = true;
520
  ghosts.forEach(ghost => {
@@ -524,7 +617,7 @@
524
  ghost.element.classList.add('bg-blue-500');
525
  }
526
  });
527
-
528
  // Set timer to end scared state
529
  if (scaredTimer) clearTimeout(scaredTimer);
530
  scaredTimer = setTimeout(() => {
@@ -539,18 +632,59 @@
539
  }, 10000);
540
  }
541
  }
542
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  // Check for ghost collisions
544
  ghosts.forEach(ghost => {
545
  const ghostX = Math.round(ghost.x);
546
  const ghostY = Math.round(ghost.y);
547
-
548
  if (ghostX === pacmanCellX && ghostY === pacmanCellY) {
549
- if (ghost.isScared) {
550
  // Eat ghost
551
  ghost.isScared = false;
552
  ghost.isEaten = true;
553
- ghost.element.classList.remove('bg-blue-500');
554
  ghost.element.classList.add('bg-gray-400');
555
  score += 200;
556
  document.getElementById('score').textContent = score;
@@ -567,14 +701,14 @@
567
  }
568
  });
569
  }
570
-
571
  // Reset positions after losing a life
572
  function resetPositions() {
573
  pacman = { x: 14, y: 23, direction: 'right', nextDirection: 'right' };
574
  document.getElementById('pacman').style.left = `${pacman.x * CELL_SIZE}px`;
575
  document.getElementById('pacman').style.top = `${pacman.y * CELL_SIZE}px`;
576
  document.getElementById('pacman').style.transform = 'rotate(0deg)';
577
-
578
  ghosts.forEach(ghost => {
579
  if (ghost.id === 'blinky' || ghost.id === 'pinky') {
580
  ghost.x = ghost.id === 'blinky' ? 13 : 14;
@@ -583,40 +717,44 @@
583
  ghost.x = ghost.id === 'inky' ? 13 : 14;
584
  ghost.y = 14;
585
  }
586
-
587
  ghost.direction = 'up';
588
  ghost.isScared = false;
589
  ghost.isEaten = false;
590
- ghost.element.classList.remove('bg-blue-500', 'bg-gray-400');
591
  ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`);
592
  ghost.element.style.left = `${ghost.x * CELL_SIZE}px`;
593
  ghost.element.style.top = `${ghost.y * CELL_SIZE}px`;
594
  });
595
-
596
  // Reset scared state
597
  scaredGhosts = false;
598
  if (scaredTimer) clearTimeout(scaredTimer);
 
 
599
  }
600
-
601
  // Game over
602
  function gameOver() {
603
  gameRunning = false;
604
  document.getElementById('final-score').textContent = score;
605
  document.getElementById('game-over').classList.remove('hidden');
606
  document.getElementById('restart-btn').classList.remove('hidden');
 
607
  }
608
-
609
  // Update display
610
  function updateDisplay() {
611
  // Update Pac-Man mouth direction
612
  const pacmanElement = document.getElementById('pacman');
613
  pacmanElement.style.clipPath = 'polygon(50% 50%, 100% 0%, 100% 100%)';
614
-
615
  // Update ghost states
616
  ghosts.forEach(ghost => {
617
  if (ghost.isScared) {
618
  // Blinking effect when scared time is almost up
619
- if (scaredTimer && Date.now() % 200 < 100) {
 
620
  ghost.element.classList.remove('bg-blue-500');
621
  ghost.element.classList.add('bg-white');
622
  } else {
@@ -626,11 +764,21 @@
626
  }
627
  });
628
  }
629
-
 
 
 
 
 
 
630
  // Event listeners
631
  document.addEventListener('keydown', (e) => {
 
 
 
 
632
  if (!gameRunning) return;
633
-
634
  switch (e.key) {
635
  case 'ArrowLeft':
636
  pacman.nextDirection = 'left';
@@ -646,15 +794,15 @@
646
  break;
647
  }
648
  });
649
-
650
  document.getElementById('restart-btn').addEventListener('click', initGame);
651
  document.getElementById('game-over-restart').addEventListener('click', () => {
652
  document.getElementById('game-over').classList.add('hidden');
653
  initGame();
654
  });
655
-
656
- // Start the game
657
- initGame();
658
  });
659
  </script>
660
  <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=alvesrt/pac-man" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
 
11
  50% { clip-path: polygon(50% 50%, 100% 40%, 100% 60%); }
12
  100% { clip-path: polygon(50% 50%, 100% 0%, 100% 100%); }
13
  }
14
+
15
  @keyframes ghost-movement {
16
  0% { transform: translateY(0); }
17
  50% { transform: translateY(-5px); }
18
  100% { transform: translateY(0); }
19
  }
20
+
21
+ @keyframes pulse {
22
+ 0% { transform: scale(1); }
23
+ 50% { transform: scale(1.2); }
24
+ 100% { transform: scale(1); }
25
+ }
26
+
27
+ @keyframes blink {
28
+ 0%, 100% { opacity: 1; }
29
+ 50% { opacity: 0.5; }
30
+ }
31
+
32
  .pacman {
33
  animation: pacman-mouth 0.5s infinite;
34
  }
35
+
36
  .ghost {
37
  animation: ghost-movement 1s infinite;
38
  }
39
+
40
  .ghost::before {
41
  content: '';
42
  position: absolute;
 
47
  top: -10px;
48
  left: 10px;
49
  }
50
+
51
  .ghost::after {
52
  content: '';
53
  position: absolute;
 
59
  left: 15px;
60
  box-shadow: 10px 0 black;
61
  }
62
+
63
  .ghost-eye {
64
  width: 6px;
65
  height: 6px;
 
69
  top: -3px;
70
  left: 13px;
71
  }
72
+
73
  .ghost-pupil {
74
  width: 2px;
75
  height: 2px;
 
79
  top: 1px;
80
  left: 1px;
81
  }
82
+
83
  .wall {
84
  background-color: #2563eb;
85
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
86
  }
87
+
88
  .dot {
89
  width: 6px;
90
  height: 6px;
 
92
  border-radius: 50%;
93
  box-shadow: 0 0 5px #fbbf24;
94
  }
95
+
96
  .power-pellet {
97
  width: 12px;
98
  height: 12px;
 
101
  box-shadow: 0 0 10px #fbbf24;
102
  animation: pulse 1s infinite;
103
  }
104
+
105
+ .fruit {
106
+ width: 16px;
107
+ height: 16px;
108
+ background-color: #dc2626;
109
+ border-radius: 8px;
110
+ box-shadow: 0 0 8px #dc2626;
111
  }
112
+
113
  #game-board {
114
  position: relative;
115
  width: 560px;
 
117
  border: 2px solid #1e40af;
118
  background-color: #1e1b4b;
119
  }
120
+
121
  .cell {
122
  width: 20px;
123
  height: 20px;
124
  position: absolute;
125
  }
126
+
127
  #score-display {
128
  font-family: 'Courier New', monospace;
129
  letter-spacing: 2px;
130
  }
131
+
132
+ #game-over, #start-screen {
133
  background-color: rgba(0, 0, 0, 0.8);
134
  z-index: 100;
135
  }
136
+
137
+ .press-enter {
138
+ animation: blink 1.5s infinite;
139
+ }
140
+
141
+ .title-shadow {
142
+ text-shadow: 0 0 10px #fbbf24, 0 0 20px #fbbf24;
143
+ }
144
+
145
+ #start-screen {
146
+ cursor: pointer;
147
+ }
148
  </style>
149
  </head>
150
  <body class="bg-gray-900 min-h-screen flex flex-col items-center justify-center p-4">
151
+ <div id="start-screen" class="absolute w-full h-full flex flex-col items-center justify-center text-white">
152
+ <h1 class="text-6xl font-bold text-yellow-400 mb-8 title-shadow">PAC-MAN</h1>
153
+ <div class="text-2xl mb-8">
154
+ <div class="flex justify-center items-center mb-4">
155
+ <div class="pacman w-10 h-10 bg-yellow-400 rounded-full mr-4"></div>
156
+ <div class="ghost w-10 h-10 bg-red-500 rounded-t-full relative"></div>
157
+ </div>
158
+ <p class="press-enter text-3xl mt-8">PRESS ENTER TO START</p>
159
+ <p class="text-xl mt-4">(or click anywhere)</p>
160
+ </div>
161
+ </div>
162
+
163
+ <div class="text-center mb-4 hidden" id="game-header">
164
  <h1 class="text-4xl font-bold text-yellow-400 mb-2">PAC-MAN</h1>
165
  <div id="score-display" class="text-2xl font-mono text-white">
166
  SCORE: <span id="score">0</span>
167
  </div>
168
  </div>
169
+
170
+ <div id="game-board" class="relative hidden"></div>
171
+
172
+ <div class="mt-4 text-white hidden" id="game-controls">
 
 
173
  <p class="mb-2">Use arrow keys to move Pac-Man</p>
174
  <button id="restart-btn" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded hidden">
175
  Play Again
176
  </button>
177
  </div>
178
+
179
  <div id="game-over" class="absolute hidden flex-col items-center justify-center text-white">
180
  <h2 class="text-4xl font-bold text-red-500 mb-4">GAME OVER</h2>
181
  <p class="text-2xl mb-4">Final Score: <span id="final-score">0</span></p>
 
183
  Play Again
184
  </button>
185
  </div>
186
+
187
  <script>
188
  document.addEventListener('DOMContentLoaded', () => {
189
  // Game constants
 
192
  const COLS = 28;
193
  const BOARD_WIDTH = COLS * CELL_SIZE;
194
  const BOARD_HEIGHT = ROWS * CELL_SIZE;
195
+ const FRUIT_DURATION = 10000; // 10 seconds in milliseconds
196
+
197
  // Game state
198
  let score = 0;
199
+ let lives = 3;
200
  let pacman = { x: 14, y: 23, direction: 'right', nextDirection: 'right' };
201
  let ghosts = [];
202
  let dots = [];
 
205
  let gameRunning = false;
206
  let scaredGhosts = false;
207
  let scaredTimer = null;
208
+ let pacmanBoost = false;
209
+ let pacmanBoostTimer = null;
210
+ let fruit = null;
211
+ let fruitTimer = null;
212
+
213
  // Maze layout (1 = wall, 0 = path, . = dot, o = power pellet)
214
  const layout = [
215
  '1111111111111111111111111111',
 
223
  '1......111....11....111....1',
224
  '111111.111111.111111.111111',
225
  '111111.111111.111111.111111',
226
+ '111111.111 111.1111',
227
  '111111.111 111111 111.1111',
228
+ '111111.111 1 1 111.1111',
229
+ '1............1 1......1',
230
  '1.1111.11111 111111 111.11',
231
+ '1.1111.11111 111.11',
232
  '1.1111.11111 111111 111.111',
233
+ '1......11111 1 1 111....1',
234
+ '111111.11111 1 1 111.1111',
235
  '111111.11111 111111 111.1111',
236
+ '111111.11111 111.1111',
237
  '1............111111......1',
238
  '1.1111.11111.111.11111.1111',
239
  '1.1111.11111.111.11111.1111',
 
245
  '1..........................1',
246
  '1111111111111111111111111111'
247
  ];
248
+
249
  // Initialize game
250
  function initGame() {
251
  score = 0;
 
253
  document.getElementById('score').textContent = score;
254
  document.getElementById('game-over').classList.add('hidden');
255
  document.getElementById('restart-btn').classList.add('hidden');
256
+
257
+ // Show game elements
258
+ document.getElementById('game-header').classList.remove('hidden');
259
+ document.getElementById('game-board').classList.remove('hidden');
260
+ document.getElementById('game-controls').classList.remove('hidden');
261
+
262
  // Clear previous game elements
263
  document.getElementById('game-board').innerHTML = '';
264
  dots = [];
265
  powerPellets = [];
266
  walls = [];
267
  ghosts = [];
268
+ fruit = null;
269
+ if (fruitTimer) clearTimeout(fruitTimer);
270
+
271
  // Create game elements based on layout
272
  for (let y = 0; y < ROWS; y++) {
273
  for (let x = 0; x < COLS; x++) {
 
276
  cellElement.className = 'cell';
277
  cellElement.style.left = `${x * CELL_SIZE}px`;
278
  cellElement.style.top = `${y * CELL_SIZE}px`;
279
+
280
  if (cell === '1') {
281
  // Wall
282
  cellElement.classList.add('wall');
 
300
  }
301
  }
302
  }
303
+
304
  // Create Pac-Man
305
  const pacmanElement = document.createElement('div');
306
  pacmanElement.id = 'pacman';
 
308
  pacmanElement.style.left = `${pacman.x * CELL_SIZE}px`;
309
  pacmanElement.style.top = `${pacman.y * CELL_SIZE}px`;
310
  document.getElementById('game-board').appendChild(pacmanElement);
311
+
312
  // Create ghosts
313
  createGhost('blinky', 13, 11, 'red');
314
  createGhost('pinky', 14, 11, 'pink');
315
  createGhost('inky', 13, 14, 'cyan');
316
  createGhost('clyde', 14, 14, 'orange');
317
+
318
  gameRunning = true;
319
  requestAnimationFrame(gameLoop);
320
+ startFruitAppearance();
321
  }
322
+
323
  function createGhost(id, x, y, color) {
324
  const ghost = {
325
  id,
 
330
  isScared: false,
331
  isEaten: false
332
  };
333
+
334
  const ghostElement = document.createElement('div');
335
  ghostElement.id = id;
336
  ghostElement.className = `ghost absolute w-5 h-5 bg-${color}-500 rounded-t-full`;
337
  ghostElement.style.left = `${x * CELL_SIZE}px`;
338
  ghostElement.style.top = `${y * CELL_SIZE}px`;
339
+
340
  // Add eyes
341
  const leftEye = document.createElement('div');
342
  leftEye.className = 'ghost-eye';
343
  leftEye.style.left = '8px';
344
+
345
  const rightEye = document.createElement('div');
346
  rightEye.className = 'ghost-eye';
347
  rightEye.style.left = '18px';
348
+
349
  const leftPupil = document.createElement('div');
350
  leftPupil.className = 'ghost-pupil';
351
+
352
  const rightPupil = document.createElement('div');
353
  rightPupil.className = 'ghost-pupil';
354
+
355
  leftEye.appendChild(leftPupil);
356
  rightEye.appendChild(rightPupil);
357
  ghostElement.appendChild(leftEye);
358
  ghostElement.appendChild(rightEye);
359
+
360
  document.getElementById('game-board').appendChild(ghostElement);
361
  ghost.element = ghostElement;
362
  ghosts.push(ghost);
363
+
364
  return ghost;
365
  }
366
+
367
  // Game loop
368
  function gameLoop(timestamp) {
369
  if (!gameRunning) return;
370
+
371
  movePacman();
372
  moveGhosts();
373
  checkCollisions();
374
  updateDisplay();
375
+
376
  if (dots.length === 0 && powerPellets.length === 0) {
377
+ // All dots and power pellets eaten - You Won!
378
  gameRunning = false;
379
  setTimeout(() => {
380
+ alert('You Won! Final Score: ' + score);
381
  initGame();
382
  }, 500);
383
  return;
384
  }
385
+
386
  requestAnimationFrame(gameLoop);
387
  }
388
+
389
  // Move Pac-Man
390
  function movePacman() {
391
  const pacmanElement = document.getElementById('pacman');
392
+
393
  // Try to change direction if there's a next direction queued
394
  if (pacman.nextDirection !== pacman.direction) {
395
  const nextX = Math.round(pacman.x);
396
  const nextY = Math.round(pacman.y);
397
+
398
  if (canMove(nextX, nextY, pacman.nextDirection)) {
399
  pacman.direction = pacman.nextDirection;
400
  }
401
  }
402
+
403
  // Calculate new position
404
  let newX = pacman.x;
405
  let newY = pacman.y;
406
+
407
  switch (pacman.direction) {
408
  case 'left':
409
+ newX -= 0.2;
410
  pacmanElement.style.transform = 'rotate(180deg)';
411
  break;
412
  case 'right':
413
+ newX += 0.2;
414
  pacmanElement.style.transform = 'rotate(0deg)';
415
  break;
416
  case 'up':
417
+ newY -= 0.2;
418
  pacmanElement.style.transform = 'rotate(-90deg)';
419
  break;
420
  case 'down':
421
+ newY += 0.2;
422
  pacmanElement.style.transform = 'rotate(90deg)';
423
  break;
424
  }
425
+
426
  // Check if new position is valid
427
  if (canMove(Math.floor(newX), Math.floor(newY), pacman.direction)) {
428
  pacman.x = newX;
429
  pacman.y = newY;
430
+
431
  // Handle tunnel/wrap-around
432
  if (pacman.x < 0) pacman.x = COLS - 1;
433
  if (pacman.x >= COLS) pacman.x = 0;
434
+
435
  // Update position
436
  pacmanElement.style.left = `${pacman.x * CELL_SIZE}px`;
437
  pacmanElement.style.top = `${pacman.y * CELL_SIZE}px`;
438
  }
439
  }
440
+
441
  // Move ghosts
442
  function moveGhosts() {
443
  ghosts.forEach(ghost => {
 
445
  // Ghost is returning to base
446
  const targetX = 13;
447
  const targetY = 11;
448
+
449
  if (ghost.x < targetX) ghost.direction = 'right';
450
  else if (ghost.x > targetX) ghost.direction = 'left';
451
  else if (ghost.y < targetY) ghost.direction = 'down';
 
465
  'left': 'right',
466
  'right': 'left'
467
  };
468
+
469
  // Don't go back the way you came
470
  const possibleDirections = directions.filter(dir => dir !== oppositeDir[ghost.direction]);
471
+
472
  // Filter to only valid moves
473
  const validDirections = possibleDirections.filter(dir => {
474
  const testX = Math.floor(ghost.x);
475
  const testY = Math.floor(ghost.y);
476
  return canMove(testX, testY, dir);
477
  });
478
+
479
  if (validDirections.length > 0) {
480
  // Choose random direction (simple AI)
481
  ghost.direction = validDirections[Math.floor(Math.random() * validDirections.length)];
482
  }
483
  }
484
+
485
  // Move ghost
486
  let newX = ghost.x;
487
  let newY = ghost.y;
488
+
489
  switch (ghost.direction) {
490
  case 'left':
491
  newX -= ghost.speed * 0.05;
 
500
  newY += ghost.speed * 0.05;
501
  break;
502
  }
503
+
504
  // Check if new position is valid
505
  if (canMove(Math.floor(newX), Math.floor(newY), ghost.direction)) {
506
  ghost.x = newX;
507
  ghost.y = newY;
508
+
509
  // Handle tunnel/wrap-around
510
  if (ghost.x < 0) ghost.x = COLS - 1;
511
  if (ghost.x >= COLS) ghost.x = 0;
512
+
513
  // Update position
514
  ghost.element.style.left = `${ghost.x * CELL_SIZE}px`;
515
  ghost.element.style.top = `${ghost.y * CELL_SIZE}px`;
516
  }
517
  });
518
  }
519
+
520
  // Check if movement is possible
521
  function canMove(x, y, direction) {
522
  // Check if out of bounds (except for tunnels)
523
  if (y < 0 || y >= ROWS) return false;
524
+
525
  // Check for walls
526
  const nextX = direction === 'left' ? x - 1 : direction === 'right' ? x + 1 : x;
527
  const nextY = direction === 'up' ? y - 1 : direction === 'down' ? y + 1 : y;
528
+
529
  // Allow tunnel wrap-around
530
  if (nextX < 0 || nextX >= COLS) {
531
  return y === 14 && (nextX < 0 || nextX >= COLS);
532
  }
533
+
534
  if (nextY < 0 || nextY >= ROWS) return false;
535
+
536
  return layout[nextY][nextX] !== '1';
537
  }
538
+
539
+ // Function to randomly place the fruit
540
+ function placeFruit() {
541
+ if (fruit) {
542
+ document.getElementById('game-board').removeChild(fruit.element);
543
+ fruit = null;
544
+ }
545
+
546
+ const emptyCells = [];
547
+ for (let y = 0; y < ROWS; y++) {
548
+ for (let x = 0; x < COLS; x++) {
549
+ if (layout[y][x] === '0') {
550
+ emptyCells.push({ x, y });
551
+ }
552
+ }
553
+ }
554
+
555
+ if (emptyCells.length > 0) {
556
+ const randomIndex = Math.floor(Math.random() * emptyCells.length);
557
+ const fruitPosition = emptyCells[randomIndex];
558
+
559
+ const fruitElement = document.createElement('div');
560
+ fruitElement.className = 'fruit absolute';
561
+ fruitElement.style.left = `${fruitPosition.x * CELL_SIZE + 2}px`;
562
+ fruitElement.style.top = `${fruitPosition.y * CELL_SIZE + 2}px`;
563
+ document.getElementById('game-board').appendChild(fruitElement);
564
+
565
+ fruit = { x: fruitPosition.x, y: fruitPosition.y, element: fruitElement };
566
+
567
+ // Set timer to remove the fruit
568
+ fruitTimer = setTimeout(() => {
569
+ if (fruit) {
570
+ document.getElementById('game-board').removeChild(fruit.element);
571
+ fruit = null;
572
+ }
573
+ }, FRUIT_DURATION);
574
+ }
575
+ }
576
+
577
+ // Function to start the fruit appearance interval
578
+ function startFruitAppearance() {
579
+ // Appear randomly after some time (e.g., between 5 to 15 seconds)
580
+ const randomDelay = Math.random() * 10000 + 5000;
581
+ setTimeout(placeFruit, randomDelay);
582
+ }
583
+
584
  // Check for collisions
585
  function checkCollisions() {
586
  const pacmanCellX = Math.round(pacman.x);
587
  const pacmanCellY = Math.round(pacman.y);
588
+
589
  // Check for dot collisions
590
  for (let i = dots.length - 1; i >= 0; i--) {
591
  const dot = dots[i];
 
597
  document.getElementById('score').textContent = score;
598
  }
599
  }
600
+
601
  // Check for power pellet collisions
602
  for (let i = powerPellets.length - 1; i >= 0; i--) {
603
  const pellet = powerPellets[i];
 
607
  powerPellets.splice(i, 1);
608
  score += 50;
609
  document.getElementById('score').textContent = score;
610
+
611
  // Make ghosts scared
612
  scaredGhosts = true;
613
  ghosts.forEach(ghost => {
 
617
  ghost.element.classList.add('bg-blue-500');
618
  }
619
  });
620
+
621
  // Set timer to end scared state
622
  if (scaredTimer) clearTimeout(scaredTimer);
623
  scaredTimer = setTimeout(() => {
 
632
  }, 10000);
633
  }
634
  }
635
+
636
+ // Check for fruit collision
637
+ if (fruit && fruit.x === pacmanCellX && fruit.y === pacmanCellY) {
638
+ // Pac-Man eats the fruit
639
+ document.getElementById('game-board').removeChild(fruit.element);
640
+ fruit = null;
641
+ score += 100; // Award points for eating the fruit
642
+ document.getElementById('score').textContent = score;
643
+
644
+ // Activate Pac-Man boost
645
+ pacmanBoost = true;
646
+ if (pacmanBoostTimer) clearTimeout(pacmanBoostTimer);
647
+ pacmanBoostTimer = setTimeout(() => {
648
+ pacmanBoost = false;
649
+ }, FRUIT_DURATION);
650
+
651
+ // Ensure ghosts become scared if a power pellet was active
652
+ if (!scaredGhosts) {
653
+ scaredGhosts = true;
654
+ ghosts.forEach(ghost => {
655
+ if (!ghost.isEaten) {
656
+ ghost.isScared = true;
657
+ ghost.element.classList.remove(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`);
658
+ ghost.element.classList.add('bg-blue-500');
659
+ }
660
+ });
661
+ if (scaredTimer) clearTimeout(scaredTimer);
662
+ scaredTimer = setTimeout(() => {
663
+ scaredGhosts = false;
664
+ ghosts.forEach(ghost => {
665
+ if (!ghost.isEaten) {
666
+ ghost.isScared = false;
667
+ ghost.element.classList.remove('bg-blue-500');
668
+ ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`);
669
+ }
670
+ });
671
+ }, FRUIT_DURATION);
672
+ }
673
+ // Schedule the next fruit appearance
674
+ startFruitAppearance();
675
+ }
676
+
677
  // Check for ghost collisions
678
  ghosts.forEach(ghost => {
679
  const ghostX = Math.round(ghost.x);
680
  const ghostY = Math.round(ghost.y);
681
+
682
  if (ghostX === pacmanCellX && ghostY === pacmanCellY) {
683
+ if (ghost.isScared && pacmanBoost) {
684
  // Eat ghost
685
  ghost.isScared = false;
686
  ghost.isEaten = true;
687
+ ghost.element.classList.remove('bg-blue-500', 'bg-white');
688
  ghost.element.classList.add('bg-gray-400');
689
  score += 200;
690
  document.getElementById('score').textContent = score;
 
701
  }
702
  });
703
  }
704
+
705
  // Reset positions after losing a life
706
  function resetPositions() {
707
  pacman = { x: 14, y: 23, direction: 'right', nextDirection: 'right' };
708
  document.getElementById('pacman').style.left = `${pacman.x * CELL_SIZE}px`;
709
  document.getElementById('pacman').style.top = `${pacman.y * CELL_SIZE}px`;
710
  document.getElementById('pacman').style.transform = 'rotate(0deg)';
711
+
712
  ghosts.forEach(ghost => {
713
  if (ghost.id === 'blinky' || ghost.id === 'pinky') {
714
  ghost.x = ghost.id === 'blinky' ? 13 : 14;
 
717
  ghost.x = ghost.id === 'inky' ? 13 : 14;
718
  ghost.y = 14;
719
  }
720
+
721
  ghost.direction = 'up';
722
  ghost.isScared = false;
723
  ghost.isEaten = false;
724
+ ghost.element.classList.remove('bg-blue-500', 'bg-gray-400', 'bg-white');
725
  ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`);
726
  ghost.element.style.left = `${ghost.x * CELL_SIZE}px`;
727
  ghost.element.style.top = `${ghost.y * CELL_SIZE}px`;
728
  });
729
+
730
  // Reset scared state
731
  scaredGhosts = false;
732
  if (scaredTimer) clearTimeout(scaredTimer);
733
+ pacmanBoost = false;
734
+ if (pacmanBoostTimer) clearTimeout(pacmanBoostTimer);
735
  }
736
+
737
  // Game over
738
  function gameOver() {
739
  gameRunning = false;
740
  document.getElementById('final-score').textContent = score;
741
  document.getElementById('game-over').classList.remove('hidden');
742
  document.getElementById('restart-btn').classList.remove('hidden');
743
+ if (fruitTimer) clearTimeout(fruitTimer);
744
  }
745
+
746
  // Update display
747
  function updateDisplay() {
748
  // Update Pac-Man mouth direction
749
  const pacmanElement = document.getElementById('pacman');
750
  pacmanElement.style.clipPath = 'polygon(50% 50%, 100% 0%, 100% 100%)';
751
+
752
  // Update ghost states
753
  ghosts.forEach(ghost => {
754
  if (ghost.isScared) {
755
  // Blinking effect when scared time is almost up
756
+ const remainingScaredTime = scaredTimer ? parseInt((scaredTimer._idleTimeout - scaredTimer._idleStart) / 1000) : 0;
757
+ if (remainingScaredTime <= 3 && Date.now() % 200 < 100) {
758
  ghost.element.classList.remove('bg-blue-500');
759
  ghost.element.classList.add('bg-white');
760
  } else {
 
764
  }
765
  });
766
  }
767
+
768
+ // Start the game when Enter is pressed or screen is clicked
769
+ function startGame() {
770
+ document.getElementById('start-screen').classList.add('hidden');
771
+ initGame();
772
+ }
773
+
774
  // Event listeners
775
  document.addEventListener('keydown', (e) => {
776
+ if (e.key === 'Enter' && !gameRunning && !document.getElementById('start-screen').classList.contains('hidden')) {
777
+ startGame();
778
+ }
779
+
780
  if (!gameRunning) return;
781
+
782
  switch (e.key) {
783
  case 'ArrowLeft':
784
  pacman.nextDirection = 'left';
 
794
  break;
795
  }
796
  });
797
+
798
  document.getElementById('restart-btn').addEventListener('click', initGame);
799
  document.getElementById('game-over-restart').addEventListener('click', () => {
800
  document.getElementById('game-over').classList.add('hidden');
801
  initGame();
802
  });
803
+
804
+ // Click on the start screen to begin
805
+ document.getElementById('start-screen').addEventListener('click', startGame);
806
  });
807
  </script>
808
  <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=alvesrt/pac-man" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>