Skip to content

Commit 8ace104

Browse files
author
Brigit Murtaugh
committed
Enhance Pacman game with collision detection, lives system, and game over screen
1 parent 1bd4eef commit 8ace104

File tree

1 file changed

+125
-2
lines changed

1 file changed

+125
-2
lines changed

pacman.html

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
<a href="#pacman-game" class="pacman-link"><h1 id="pacman-game">Pacman Game</h1></a>
2626
<canvas id="pacmanCanvas" width="896" height="992"></canvas>
27-
<p>Use arrow keys to move Pacman. Eat all the features!</p>
27+
<p>Use arrow keys to move Pacman. Collect all the whale icons while avoiding the monsters.</p>
2828
<script>
2929
// Larger Pacman game (dev container themed, fewer collectibles, bigger whales)
3030
const canvas = document.getElementById('pacmanCanvas');
@@ -62,6 +62,8 @@
6262
let pacman = { x: 14, y: 17, dx: 0, dy: 0, nextDx: 0, nextDy: 0 };
6363
let score = 0;
6464
let dots = 0;
65+
let gameOver = false;
66+
let lives = 3;
6567
for (let row of map) for (let c of row) if (c === '.' || c === 'o') dots++;
6668
function drawMap() {
6769
for (let y = 0; y < map.length; y++) {
@@ -238,6 +240,8 @@
238240
if (canMove(pacman.x + pacman.dx, pacman.y + pacman.dy)) {
239241
pacman.x += pacman.dx;
240242
pacman.y += pacman.dy;
243+
// Check for collisions after each move
244+
checkCollisions();
241245
}
242246
// Wrap
243247
if (pacman.x < 0) pacman.x = map[0].length - 1;
@@ -257,9 +261,112 @@
257261
ctx.fillStyle = '#FFF';
258262
ctx.font = '28px Arial';
259263
ctx.fillText('Score: ' + score, 20, canvas.height - 20);
264+
265+
// Draw lives
266+
ctx.fillStyle = '#FFFF00';
267+
ctx.font = '28px Arial';
268+
ctx.fillText('Lives: ' + lives, canvas.width - 150, canvas.height - 20);
269+
}
270+
271+
// Check if Pacman collides with any monster
272+
function checkCollisions() {
273+
for (const monster of globalThis.monsterStates) {
274+
if (monster.x === pacman.x && monster.y === pacman.y) {
275+
lives--;
276+
if (lives <= 0) {
277+
gameOver = true;
278+
} else {
279+
// Reset Pacman position
280+
pacman.x = 14;
281+
pacman.y = 17;
282+
pacman.dx = 0;
283+
pacman.dy = 0;
284+
pacman.nextDx = 0;
285+
pacman.nextDy = 0;
286+
}
287+
return true;
288+
}
289+
}
290+
return false;
291+
}
292+
293+
// Draw game over screen
294+
function drawGameOver() {
295+
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
296+
ctx.fillRect(0, 0, canvas.width, canvas.height);
297+
298+
ctx.fillStyle = '#e74c3c';
299+
ctx.font = '48px Arial';
300+
ctx.textAlign = 'center';
301+
ctx.fillText('GAME OVER', canvas.width/2, canvas.height/2 - 50);
302+
303+
ctx.fillStyle = '#FFF';
304+
ctx.font = '24px Arial';
305+
ctx.fillText('Final Score: ' + score, canvas.width/2, canvas.height/2);
306+
307+
ctx.fillStyle = '#25d6a2';
308+
ctx.font = '28px Arial';
309+
ctx.fillText('Press SPACE to restart', canvas.width/2, canvas.height/2 + 50);
310+
311+
ctx.textAlign = 'left'; // Reset text align
312+
}
313+
314+
// Reset game state
315+
function resetGame() {
316+
// Reset map (restore dots)
317+
map = [
318+
'############################',
319+
'# ....##.... ....#',
320+
'#.####.#####.##.#####.####.#',
321+
'#o####.#####.##.#####.####o#',
322+
'#.####.#####.##.#####.####.#',
323+
'# #',
324+
'#.####.##.########.##.####.#',
325+
'#.####.##.########.##.####.#',
326+
'# ## ## ## #',
327+
'######.##### ## #####.######',
328+
'######.##### ## #####.######',
329+
'######.## ##.######',
330+
'######.## ######## ##.######',
331+
'######.## ######## ##.######',
332+
'# ....##.... ....#',
333+
'#.####.#####.##.#####.####.#',
334+
'#.####.#####.##.#####.####.#',
335+
'#o..## ##..o#',
336+
'###.##.##.########.##.##.###',
337+
'###.##.##.########.##.##.###',
338+
'# ## ## ## #',
339+
'#.##########.##.##########.#',
340+
'#.##########.##.##########.#',
341+
'# #',
342+
'############################'
343+
];
344+
345+
// Reset pacman
346+
pacman = { x: 14, y: 17, dx: 0, dy: 0, nextDx: 0, nextDy: 0 };
347+
348+
// Reset monsters to original positions
349+
globalThis.monsterStates = monsters.map(m => ({...m, dx: 0, dy: 0}));
350+
351+
// Reset game state
352+
score = 0;
353+
lives = 3;
354+
gameOver = false;
355+
dots = 0;
356+
for (let row of map) for (let c of row) if (c === '.' || c === 'o') dots++;
357+
358+
// Restart game loop
359+
requestAnimationFrame(gameLoop);
260360
}
261361

262362
document.addEventListener('keydown', e => {
363+
if (gameOver) {
364+
if (e.key === ' ' || e.code === 'Space') {
365+
resetGame();
366+
}
367+
return;
368+
}
369+
263370
if (["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.key)) {
264371
e.preventDefault();
265372
let moved = false;
@@ -290,20 +397,36 @@
290397
function gameLoop(timestamp) {
291398
ctx.clearRect(0, 0, canvas.width, canvas.height);
292399
drawMap();
400+
401+
if (gameOver) {
402+
drawGameOver();
403+
return;
404+
}
405+
293406
if (!lastMonsterMove) lastMonsterMove = timestamp;
294407
if (timestamp - lastMonsterMove > MONSTER_MOVE_INTERVAL) {
295408
moveMonsters();
296409
lastMonsterMove = timestamp;
410+
// Check for collisions after monsters move
411+
checkCollisions();
297412
}
413+
298414
drawMonsters();
299415
drawPacman();
300416
drawScore();
417+
301418
if (score >= dots) {
302419
ctx.fillStyle = '#25d6a2';
303420
ctx.font = '48px Arial';
304-
ctx.fillText('All Features Collected!', canvas.width/2 - 260, canvas.height/2);
421+
ctx.textAlign = 'center';
422+
ctx.fillText('All Features Collected!', canvas.width/2, canvas.height/2);
423+
ctx.font = '28px Arial';
424+
ctx.fillText('Press SPACE to play again', canvas.width/2, canvas.height/2 + 50);
425+
gameOver = true;
426+
ctx.textAlign = 'left';
305427
return;
306428
}
429+
307430
requestAnimationFrame(gameLoop);
308431
}
309432

0 commit comments

Comments
 (0)