|
20 | 20 | text-decoration: underline; |
21 | 21 | cursor: pointer; |
22 | 22 | } |
| 23 | +.pacman-button { |
| 24 | + background-color: #25d6a2; |
| 25 | + border: none; |
| 26 | + color: #000; |
| 27 | + padding: 10px 20px; |
| 28 | + text-align: center; |
| 29 | + font-size: 16px; |
| 30 | + margin: 10px auto; |
| 31 | + cursor: pointer; |
| 32 | + display: block; |
| 33 | + border-radius: 5px; |
| 34 | + font-weight: bold; |
| 35 | + transition: background-color 0.3s; |
| 36 | +} |
| 37 | +.pacman-button:hover { |
| 38 | + background-color: #1eb589; |
| 39 | +} |
23 | 40 | </style> |
24 | 41 |
|
25 | 42 | <a href="#pacman-game" class="pacman-link"><h1 id="pacman-game">Pacman Game</h1></a> |
26 | 43 | <canvas id="pacmanCanvas" width="896" height="992"></canvas> |
27 | 44 | <p>Use arrow keys to move Pacman. Collect all the whale icons while avoiding the monsters.</p> |
| 45 | +<button id="restartButton" class="pacman-button">Restart Game</button> |
28 | 46 | <script> |
29 | 47 | // Larger Pacman game (dev container themed, fewer collectibles, bigger whales) |
30 | 48 | const canvas = document.getElementById('pacmanCanvas'); |
31 | 49 | const ctx = canvas.getContext('2d'); |
32 | 50 | const tileSize = 32; |
33 | 51 | const MOVE_INTERVAL = 80; // ms, decrease for slightly faster speed |
34 | 52 | // Fewer collectibles: remove about half the dots |
35 | | -const map = [ |
| 53 | +let map = [ |
36 | 54 | '############################', |
37 | 55 | '# ....##.... ....#', |
38 | 56 | '#.####.#####.##.#####.####.#', |
|
306 | 324 |
|
307 | 325 | ctx.fillStyle = '#25d6a2'; |
308 | 326 | ctx.font = '28px Arial'; |
309 | | - ctx.fillText('Press SPACE to restart', canvas.width/2, canvas.height/2 + 50); |
| 327 | + ctx.fillText('Press R to restart', canvas.width/2, canvas.height/2 + 50); |
310 | 328 |
|
311 | 329 | ctx.textAlign = 'left'; // Reset text align |
312 | 330 | } |
|
348 | 366 | // Reset monsters to original positions |
349 | 367 | globalThis.monsterStates = monsters.map(m => ({...m, dx: 0, dy: 0})); |
350 | 368 |
|
| 369 | + // Ensure no monsters are too close to Pacman at start |
| 370 | + for (const monster of globalThis.monsterStates) { |
| 371 | + const distX = Math.abs(monster.x - pacman.x); |
| 372 | + const distY = Math.abs(monster.y - pacman.y); |
| 373 | + |
| 374 | + // If monster is within 3 tiles of Pacman, move it to a different position |
| 375 | + if (distX + distY < 3) { |
| 376 | + // Find alternative positions that are valid paths and not close to Pacman |
| 377 | + const alternatives = []; |
| 378 | + for (let y = 1; y < map.length - 1; y++) { |
| 379 | + for (let x = 1; x < map[0].length - 1; x++) { |
| 380 | + if (map[y][x] !== '#') { |
| 381 | + const newDistX = Math.abs(x - pacman.x); |
| 382 | + const newDistY = Math.abs(y - pacman.y); |
| 383 | + if (newDistX + distY >= 5) { |
| 384 | + alternatives.push({x, y}); |
| 385 | + } |
| 386 | + } |
| 387 | + } |
| 388 | + } |
| 389 | + |
| 390 | + if (alternatives.length > 0) { |
| 391 | + // Choose a random alternative position |
| 392 | + const newPos = alternatives[Math.floor(Math.random() * alternatives.length)]; |
| 393 | + monster.x = newPos.x; |
| 394 | + monster.y = newPos.y; |
| 395 | + } |
| 396 | + } |
| 397 | + } |
| 398 | + |
351 | 399 | // Reset game state |
352 | 400 | score = 0; |
353 | 401 | lives = 3; |
|
360 | 408 | } |
361 | 409 |
|
362 | 410 | document.addEventListener('keydown', e => { |
| 411 | + // Prevent scrolling for both arrow keys and spacebar |
| 412 | + if (e.key === ' ' || e.code === 'Space' || ["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.key)) { |
| 413 | + e.preventDefault(); |
| 414 | + } |
| 415 | + |
363 | 416 | if (gameOver) { |
364 | | - if (e.key === ' ' || e.code === 'Space') { |
| 417 | + if (e.key === ' ' || e.code === 'Space' || e.key === 'r' || e.key === 'R') { |
365 | 418 | resetGame(); |
366 | 419 | } |
367 | 420 | return; |
368 | 421 | } |
369 | 422 |
|
370 | 423 | if (["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.key)) { |
371 | | - e.preventDefault(); |
372 | 424 | let moved = false; |
373 | 425 | if (e.key === 'ArrowUp') { pacman.nextDx = 0; pacman.nextDy = -1; moved = true; } |
374 | 426 | if (e.key === 'ArrowDown') { pacman.nextDx = 0; pacman.nextDy = 1; moved = true; } |
|
421 | 473 | ctx.textAlign = 'center'; |
422 | 474 | ctx.fillText('All Features Collected!', canvas.width/2, canvas.height/2); |
423 | 475 | ctx.font = '28px Arial'; |
424 | | - ctx.fillText('Press SPACE to play again', canvas.width/2, canvas.height/2 + 50); |
| 476 | + ctx.fillText('Press R to play again', canvas.width/2, canvas.height/2 + 50); |
425 | 477 | gameOver = true; |
426 | 478 | ctx.textAlign = 'left'; |
427 | 479 | return; |
|
431 | 483 | } |
432 | 484 |
|
433 | 485 | requestAnimationFrame(gameLoop); |
| 486 | + |
| 487 | +// Add event listener for the restart button |
| 488 | +document.getElementById('restartButton').addEventListener('click', function() { |
| 489 | + if (gameOver) { |
| 490 | + resetGame(); |
| 491 | + } else { |
| 492 | + // If the game is still in progress, ask for confirmation |
| 493 | + if (confirm('Are you sure you want to restart the game?')) { |
| 494 | + resetGame(); |
| 495 | + } |
| 496 | + } |
| 497 | +}); |
434 | 498 | </script> |
435 | 499 |
|
436 | 500 | <!-- Monster Key --> |
|
0 commit comments