|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Pac-Man Game</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<style> |
|
@keyframes pacman-mouth { |
|
0% { clip-path: polygon(50% 50%, 100% 0%, 100% 100%); } |
|
50% { clip-path: polygon(50% 50%, 100% 40%, 100% 60%); } |
|
100% { clip-path: polygon(50% 50%, 100% 0%, 100% 100%); } |
|
} |
|
|
|
@keyframes ghost-movement { |
|
0% { transform: translateY(0); } |
|
50% { transform: translateY(-5px); } |
|
100% { transform: translateY(0); } |
|
} |
|
|
|
@keyframes pulse { |
|
0% { transform: scale(1); } |
|
50% { transform: scale(1.2); } |
|
100% { transform: scale(1); } |
|
} |
|
|
|
@keyframes blink { |
|
0%, 100% { opacity: 1; } |
|
50% { opacity: 0.5; } |
|
} |
|
|
|
.pacman { |
|
animation: pacman-mouth 0.5s infinite; |
|
} |
|
|
|
.ghost { |
|
animation: ghost-movement 1s infinite; |
|
} |
|
|
|
.ghost::before { |
|
content: ''; |
|
position: absolute; |
|
width: 20px; |
|
height: 10px; |
|
background: white; |
|
border-radius: 100px 100px 0 0; |
|
top: -10px; |
|
left: 10px; |
|
} |
|
|
|
.ghost::after { |
|
content: ''; |
|
position: absolute; |
|
width: 4px; |
|
height: 4px; |
|
background: black; |
|
border-radius: 50%; |
|
top: -5px; |
|
left: 15px; |
|
box-shadow: 10px 0 black; |
|
} |
|
|
|
.ghost-eye { |
|
width: 6px; |
|
height: 6px; |
|
background: white; |
|
border-radius: 50%; |
|
position: absolute; |
|
top: -3px; |
|
left: 13px; |
|
} |
|
|
|
.ghost-pupil { |
|
width: 2px; |
|
height: 2px; |
|
background: black; |
|
border-radius: 50%; |
|
position: absolute; |
|
top: 1px; |
|
left: 1px; |
|
} |
|
|
|
.wall { |
|
background-color: #2563eb; |
|
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5); |
|
} |
|
|
|
.dot { |
|
width: 6px; |
|
height: 6px; |
|
background-color: #fbbf24; |
|
border-radius: 50%; |
|
box-shadow: 0 0 5px #fbbf24; |
|
} |
|
|
|
.power-pellet { |
|
width: 12px; |
|
height: 12px; |
|
background-color: #fbbf24; |
|
border-radius: 50%; |
|
box-shadow: 0 0 10px #fbbf24; |
|
animation: pulse 1s infinite; |
|
} |
|
|
|
.fruit { |
|
width: 16px; |
|
height: 16px; |
|
background-color: #dc2626; |
|
border-radius: 8px; |
|
box-shadow: 0 0 8px #dc2626; |
|
} |
|
|
|
#game-board { |
|
position: relative; |
|
width: 560px; |
|
height: 620px; |
|
border: 2px solid #1e40af; |
|
background-color: #1e1b4b; |
|
} |
|
|
|
.cell { |
|
width: 20px; |
|
height: 20px; |
|
position: absolute; |
|
} |
|
|
|
#score-display { |
|
font-family: 'Courier New', monospace; |
|
letter-spacing: 2px; |
|
} |
|
|
|
#game-over, #start-screen { |
|
background-color: rgba(0, 0, 0, 0.8); |
|
z-index: 100; |
|
} |
|
|
|
.press-enter { |
|
animation: blink 1.5s infinite; |
|
} |
|
|
|
.title-shadow { |
|
text-shadow: 0 0 10px #fbbf24, 0 0 20px #fbbf24; |
|
} |
|
|
|
#start-screen { |
|
cursor: pointer; |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-900 min-h-screen flex flex-col items-center justify-center p-4"> |
|
<div id="start-screen" class="absolute w-full h-full flex flex-col items-center justify-center text-white"> |
|
<h1 class="text-6xl font-bold text-yellow-400 mb-8 title-shadow">PAC-MAN</h1> |
|
<div class="text-2xl mb-8"> |
|
<div class="flex justify-center items-center mb-4"> |
|
<div class="pacman w-10 h-10 bg-yellow-400 rounded-full mr-4"></div> |
|
<div class="ghost w-10 h-10 bg-red-500 rounded-t-full relative"></div> |
|
</div> |
|
<p class="press-enter text-3xl mt-8">PRESS ENTER TO START</p> |
|
<p class="text-xl mt-4">(or click anywhere)</p> |
|
</div> |
|
</div> |
|
|
|
<div class="text-center mb-4 hidden" id="game-header"> |
|
<h1 class="text-4xl font-bold text-yellow-400 mb-2">PAC-MAN</h1> |
|
<div id="score-display" class="text-2xl font-mono text-white"> |
|
SCORE: <span id="score">0</span> |
|
</div> |
|
</div> |
|
|
|
<div id="game-board" class="relative hidden"></div> |
|
|
|
<div class="mt-4 text-white hidden" id="game-controls"> |
|
<p class="mb-2">Use arrow keys to move Pac-Man</p> |
|
<button id="restart-btn" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded hidden"> |
|
Play Again |
|
</button> |
|
</div> |
|
|
|
<div id="game-over" class="absolute hidden flex-col items-center justify-center text-white"> |
|
<h2 class="text-4xl font-bold text-red-500 mb-4">GAME OVER</h2> |
|
<p class="text-2xl mb-4">Final Score: <span id="final-score">0</span></p> |
|
<button id="game-over-restart" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> |
|
Play Again |
|
</button> |
|
</div> |
|
|
|
<script> |
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
|
const CELL_SIZE = 20; |
|
const ROWS = 31; |
|
const COLS = 28; |
|
const BOARD_WIDTH = COLS * CELL_SIZE; |
|
const BOARD_HEIGHT = ROWS * CELL_SIZE; |
|
const FRUIT_DURATION = 10000; |
|
|
|
|
|
let score = 0; |
|
let lives = 3; |
|
let pacman = { x: 14, y: 23, direction: 'right', nextDirection: 'right' }; |
|
let ghosts = []; |
|
let dots = []; |
|
let powerPellets = []; |
|
let walls = []; |
|
let gameRunning = false; |
|
let scaredGhosts = false; |
|
let scaredTimer = null; |
|
let pacmanBoost = false; |
|
let pacmanBoostTimer = null; |
|
let fruit = null; |
|
let fruitTimer = null; |
|
|
|
|
|
const layout = [ |
|
'1111111111111111111111111111', |
|
'1............o............1', |
|
'1.1111.11111.111.11111.1111', |
|
'1.1111.11111.111.11111.1111', |
|
'1.1111.11111.111.11111.1111', |
|
'1..........................1', |
|
'1.1111.111.111111.111.1111', |
|
'1.1111.111.111111.111.1111', |
|
'1......111....11....111....1', |
|
'111111.111111.111111.111111', |
|
'111111.111111.111111.111111', |
|
'111111.111 111.1111', |
|
'111111.111 111111 111.1111', |
|
'111111.111 1 1 111.1111', |
|
'1............1 1......1', |
|
'1.1111.11111 111111 111.11', |
|
'1.1111.11111 111.11', |
|
'1.1111.11111 111111 111.111', |
|
'1......11111 1 1 111....1', |
|
'111111.11111 1 1 111.1111', |
|
'111111.11111 111111 111.1111', |
|
'111111.11111 111.1111', |
|
'1............111111......1', |
|
'1.1111.11111.111.11111.1111', |
|
'1.1111.11111.111.11111.1111', |
|
'1...o.......111....o.....1', |
|
'111.111.111.111111.111.1111', |
|
'111.111.111.111111.111.1111', |
|
'1......111....11....111....1', |
|
'1.11111111111.111.1111111.1', |
|
'1..........................1', |
|
'1111111111111111111111111111' |
|
]; |
|
|
|
|
|
function initGame() { |
|
score = 0; |
|
lives = 3; |
|
document.getElementById('score').textContent = score; |
|
document.getElementById('game-over').classList.add('hidden'); |
|
document.getElementById('restart-btn').classList.add('hidden'); |
|
|
|
|
|
document.getElementById('game-header').classList.remove('hidden'); |
|
document.getElementById('game-board').classList.remove('hidden'); |
|
document.getElementById('game-controls').classList.remove('hidden'); |
|
|
|
|
|
document.getElementById('game-board').innerHTML = ''; |
|
dots = []; |
|
powerPellets = []; |
|
walls = []; |
|
ghosts = []; |
|
fruit = null; |
|
if (fruitTimer) clearTimeout(fruitTimer); |
|
|
|
|
|
for (let y = 0; y < ROWS; y++) { |
|
for (let x = 0; x < COLS; x++) { |
|
const cell = layout[y][x]; |
|
const cellElement = document.createElement('div'); |
|
cellElement.className = 'cell'; |
|
cellElement.style.left = `${x * CELL_SIZE}px`; |
|
cellElement.style.top = `${y * CELL_SIZE}px`; |
|
|
|
if (cell === '1') { |
|
|
|
cellElement.classList.add('wall'); |
|
walls.push({ x, y }); |
|
} else if (cell === '.') { |
|
|
|
const dot = document.createElement('div'); |
|
dot.className = 'dot'; |
|
dot.style.left = `${x * CELL_SIZE + 7}px`; |
|
dot.style.top = `${y * CELL_SIZE + 7}px`; |
|
document.getElementById('game-board').appendChild(dot); |
|
dots.push({ x, y, element: dot }); |
|
} else if (cell === 'o') { |
|
|
|
const pellet = document.createElement('div'); |
|
pellet.className = 'power-pellet'; |
|
pellet.style.left = `${x * CELL_SIZE + 4}px`; |
|
pellet.style.top = `${y * CELL_SIZE + 4}px`; |
|
document.getElementById('game-board').appendChild(pellet); |
|
powerPellets.push({ x, y, element: pellet }); |
|
} |
|
} |
|
} |
|
|
|
|
|
const pacmanElement = document.createElement('div'); |
|
pacmanElement.id = 'pacman'; |
|
pacmanElement.className = 'pacman absolute w-5 h-5 bg-yellow-400 rounded-full'; |
|
pacmanElement.style.left = `${pacman.x * CELL_SIZE}px`; |
|
pacmanElement.style.top = `${pacman.y * CELL_SIZE}px`; |
|
document.getElementById('game-board').appendChild(pacmanElement); |
|
|
|
|
|
createGhost('blinky', 13, 11, 'red'); |
|
createGhost('pinky', 14, 11, 'pink'); |
|
createGhost('inky', 13, 14, 'cyan'); |
|
createGhost('clyde', 14, 14, 'orange'); |
|
|
|
gameRunning = true; |
|
requestAnimationFrame(gameLoop); |
|
startFruitAppearance(); |
|
} |
|
|
|
function createGhost(id, x, y, color) { |
|
const ghost = { |
|
id, |
|
x, |
|
y, |
|
direction: 'up', |
|
speed: 0.8, |
|
isScared: false, |
|
isEaten: false |
|
}; |
|
|
|
const ghostElement = document.createElement('div'); |
|
ghostElement.id = id; |
|
ghostElement.className = `ghost absolute w-5 h-5 bg-${color}-500 rounded-t-full`; |
|
ghostElement.style.left = `${x * CELL_SIZE}px`; |
|
ghostElement.style.top = `${y * CELL_SIZE}px`; |
|
|
|
|
|
const leftEye = document.createElement('div'); |
|
leftEye.className = 'ghost-eye'; |
|
leftEye.style.left = '8px'; |
|
|
|
const rightEye = document.createElement('div'); |
|
rightEye.className = 'ghost-eye'; |
|
rightEye.style.left = '18px'; |
|
|
|
const leftPupil = document.createElement('div'); |
|
leftPupil.className = 'ghost-pupil'; |
|
|
|
const rightPupil = document.createElement('div'); |
|
rightPupil.className = 'ghost-pupil'; |
|
|
|
leftEye.appendChild(leftPupil); |
|
rightEye.appendChild(rightPupil); |
|
ghostElement.appendChild(leftEye); |
|
ghostElement.appendChild(rightEye); |
|
|
|
document.getElementById('game-board').appendChild(ghostElement); |
|
ghost.element = ghostElement; |
|
ghosts.push(ghost); |
|
|
|
return ghost; |
|
} |
|
|
|
|
|
function gameLoop(timestamp) { |
|
if (!gameRunning) return; |
|
|
|
movePacman(); |
|
moveGhosts(); |
|
checkCollisions(); |
|
updateDisplay(); |
|
|
|
if (dots.length === 0 && powerPellets.length === 0) { |
|
|
|
gameRunning = false; |
|
setTimeout(() => { |
|
alert('You Won! Final Score: ' + score); |
|
initGame(); |
|
}, 500); |
|
return; |
|
} |
|
|
|
requestAnimationFrame(gameLoop); |
|
} |
|
|
|
|
|
function movePacman() { |
|
const pacmanElement = document.getElementById('pacman'); |
|
|
|
|
|
if (pacman.nextDirection !== pacman.direction) { |
|
const nextX = Math.round(pacman.x); |
|
const nextY = Math.round(pacman.y); |
|
|
|
if (canMove(nextX, nextY, pacman.nextDirection)) { |
|
pacman.direction = pacman.nextDirection; |
|
} |
|
} |
|
|
|
|
|
let newX = pacman.x; |
|
let newY = pacman.y; |
|
|
|
switch (pacman.direction) { |
|
case 'left': |
|
newX -= 0.2; |
|
pacmanElement.style.transform = 'rotate(180deg)'; |
|
break; |
|
case 'right': |
|
newX += 0.2; |
|
pacmanElement.style.transform = 'rotate(0deg)'; |
|
break; |
|
case 'up': |
|
newY -= 0.2; |
|
pacmanElement.style.transform = 'rotate(-90deg)'; |
|
break; |
|
case 'down': |
|
newY += 0.2; |
|
pacmanElement.style.transform = 'rotate(90deg)'; |
|
break; |
|
} |
|
|
|
|
|
if (canMove(Math.floor(newX), Math.floor(newY), pacman.direction)) { |
|
pacman.x = newX; |
|
pacman.y = newY; |
|
|
|
|
|
if (pacman.x < 0) pacman.x = COLS - 1; |
|
if (pacman.x >= COLS) pacman.x = 0; |
|
|
|
|
|
pacmanElement.style.left = `${pacman.x * CELL_SIZE}px`; |
|
pacmanElement.style.top = `${pacman.y * CELL_SIZE}px`; |
|
} |
|
} |
|
|
|
|
|
function moveGhosts() { |
|
ghosts.forEach(ghost => { |
|
if (ghost.isEaten) { |
|
|
|
const targetX = 13; |
|
const targetY = 11; |
|
|
|
if (ghost.x < targetX) ghost.direction = 'right'; |
|
else if (ghost.x > targetX) ghost.direction = 'left'; |
|
else if (ghost.y < targetY) ghost.direction = 'down'; |
|
else if (ghost.y > targetY) ghost.direction = 'up'; |
|
else { |
|
ghost.isEaten = false; |
|
ghost.isScared = false; |
|
ghost.element.classList.remove('bg-blue-500'); |
|
ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`); |
|
} |
|
} else { |
|
|
|
const directions = ['up', 'down', 'left', 'right']; |
|
const oppositeDir = { |
|
'up': 'down', |
|
'down': 'up', |
|
'left': 'right', |
|
'right': 'left' |
|
}; |
|
|
|
|
|
const possibleDirections = directions.filter(dir => dir !== oppositeDir[ghost.direction]); |
|
|
|
|
|
const validDirections = possibleDirections.filter(dir => { |
|
const testX = Math.floor(ghost.x); |
|
const testY = Math.floor(ghost.y); |
|
return canMove(testX, testY, dir); |
|
}); |
|
|
|
if (validDirections.length > 0) { |
|
|
|
ghost.direction = validDirections[Math.floor(Math.random() * validDirections.length)]; |
|
} |
|
} |
|
|
|
|
|
let newX = ghost.x; |
|
let newY = ghost.y; |
|
|
|
switch (ghost.direction) { |
|
case 'left': |
|
newX -= ghost.speed * 0.05; |
|
break; |
|
case 'right': |
|
newX += ghost.speed * 0.05; |
|
break; |
|
case 'up': |
|
newY -= ghost.speed * 0.05; |
|
break; |
|
case 'down': |
|
newY += ghost.speed * 0.05; |
|
break; |
|
} |
|
|
|
|
|
if (canMove(Math.floor(newX), Math.floor(newY), ghost.direction)) { |
|
ghost.x = newX; |
|
ghost.y = newY; |
|
|
|
|
|
if (ghost.x < 0) ghost.x = COLS - 1; |
|
if (ghost.x >= COLS) ghost.x = 0; |
|
|
|
|
|
ghost.element.style.left = `${ghost.x * CELL_SIZE}px`; |
|
ghost.element.style.top = `${ghost.y * CELL_SIZE}px`; |
|
} |
|
}); |
|
} |
|
|
|
|
|
function canMove(x, y, direction) { |
|
|
|
if (y < 0 || y >= ROWS) return false; |
|
|
|
|
|
const nextX = direction === 'left' ? x - 1 : direction === 'right' ? x + 1 : x; |
|
const nextY = direction === 'up' ? y - 1 : direction === 'down' ? y + 1 : y; |
|
|
|
|
|
if (nextX < 0 || nextX >= COLS) { |
|
return y === 14 && (nextX < 0 || nextX >= COLS); |
|
} |
|
|
|
if (nextY < 0 || nextY >= ROWS) return false; |
|
|
|
return layout[nextY][nextX] !== '1'; |
|
} |
|
|
|
|
|
function placeFruit() { |
|
if (fruit) { |
|
document.getElementById('game-board').removeChild(fruit.element); |
|
fruit = null; |
|
} |
|
|
|
const emptyCells = []; |
|
for (let y = 0; y < ROWS; y++) { |
|
for (let x = 0; x < COLS; x++) { |
|
if (layout[y][x] === '0') { |
|
emptyCells.push({ x, y }); |
|
} |
|
} |
|
} |
|
|
|
if (emptyCells.length > 0) { |
|
const randomIndex = Math.floor(Math.random() * emptyCells.length); |
|
const fruitPosition = emptyCells[randomIndex]; |
|
|
|
const fruitElement = document.createElement('div'); |
|
fruitElement.className = 'fruit absolute'; |
|
fruitElement.style.left = `${fruitPosition.x * CELL_SIZE + 2}px`; |
|
fruitElement.style.top = `${fruitPosition.y * CELL_SIZE + 2}px`; |
|
document.getElementById('game-board').appendChild(fruitElement); |
|
|
|
fruit = { x: fruitPosition.x, y: fruitPosition.y, element: fruitElement }; |
|
|
|
|
|
fruitTimer = setTimeout(() => { |
|
if (fruit) { |
|
document.getElementById('game-board').removeChild(fruit.element); |
|
fruit = null; |
|
} |
|
}, FRUIT_DURATION); |
|
} |
|
} |
|
|
|
|
|
function startFruitAppearance() { |
|
|
|
const randomDelay = Math.random() * 10000 + 5000; |
|
setTimeout(placeFruit, randomDelay); |
|
} |
|
|
|
|
|
function checkCollisions() { |
|
const pacmanCellX = Math.round(pacman.x); |
|
const pacmanCellY = Math.round(pacman.y); |
|
|
|
|
|
for (let i = dots.length - 1; i >= 0; i--) { |
|
const dot = dots[i]; |
|
if (dot.x === pacmanCellX && dot.y === pacmanCellY) { |
|
|
|
document.getElementById('game-board').removeChild(dot.element); |
|
dots.splice(i, 1); |
|
score += 10; |
|
document.getElementById('score').textContent = score; |
|
} |
|
} |
|
|
|
|
|
for (let i = powerPellets.length - 1; i >= 0; i--) { |
|
const pellet = powerPellets[i]; |
|
if (pellet.x === pacmanCellX && pellet.y === pacmanCellY) { |
|
|
|
document.getElementById('game-board').removeChild(pellet.element); |
|
powerPellets.splice(i, 1); |
|
score += 50; |
|
document.getElementById('score').textContent = score; |
|
|
|
|
|
scaredGhosts = true; |
|
ghosts.forEach(ghost => { |
|
if (!ghost.isEaten) { |
|
ghost.isScared = true; |
|
ghost.element.classList.remove(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`); |
|
ghost.element.classList.add('bg-blue-500'); |
|
} |
|
}); |
|
|
|
|
|
if (scaredTimer) clearTimeout(scaredTimer); |
|
scaredTimer = setTimeout(() => { |
|
scaredGhosts = false; |
|
ghosts.forEach(ghost => { |
|
if (!ghost.isEaten) { |
|
ghost.isScared = false; |
|
ghost.element.classList.remove('bg-blue-500'); |
|
ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`); |
|
} |
|
}); |
|
}, 10000); |
|
} |
|
} |
|
|
|
|
|
if (fruit && fruit.x === pacmanCellX && fruit.y === pacmanCellY) { |
|
|
|
document.getElementById('game-board').removeChild(fruit.element); |
|
fruit = null; |
|
score += 100; |
|
document.getElementById('score').textContent = score; |
|
|
|
|
|
pacmanBoost = true; |
|
if (pacmanBoostTimer) clearTimeout(pacmanBoostTimer); |
|
pacmanBoostTimer = setTimeout(() => { |
|
pacmanBoost = false; |
|
}, FRUIT_DURATION); |
|
|
|
|
|
if (!scaredGhosts) { |
|
scaredGhosts = true; |
|
ghosts.forEach(ghost => { |
|
if (!ghost.isEaten) { |
|
ghost.isScared = true; |
|
ghost.element.classList.remove(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`); |
|
ghost.element.classList.add('bg-blue-500'); |
|
} |
|
}); |
|
if (scaredTimer) clearTimeout(scaredTimer); |
|
scaredTimer = setTimeout(() => { |
|
scaredGhosts = false; |
|
ghosts.forEach(ghost => { |
|
if (!ghost.isEaten) { |
|
ghost.isScared = false; |
|
ghost.element.classList.remove('bg-blue-500'); |
|
ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`); |
|
} |
|
}); |
|
}, FRUIT_DURATION); |
|
} |
|
|
|
startFruitAppearance(); |
|
} |
|
|
|
|
|
ghosts.forEach(ghost => { |
|
const ghostX = Math.round(ghost.x); |
|
const ghostY = Math.round(ghost.y); |
|
|
|
if (ghostX === pacmanCellX && ghostY === pacmanCellY) { |
|
if (ghost.isScared && pacmanBoost) { |
|
|
|
ghost.isScared = false; |
|
ghost.isEaten = true; |
|
ghost.element.classList.remove('bg-blue-500', 'bg-white'); |
|
ghost.element.classList.add('bg-gray-400'); |
|
score += 200; |
|
document.getElementById('score').textContent = score; |
|
} else if (!ghost.isEaten) { |
|
|
|
lives--; |
|
if (lives <= 0) { |
|
gameOver(); |
|
} else { |
|
|
|
resetPositions(); |
|
} |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
function resetPositions() { |
|
pacman = { x: 14, y: 23, direction: 'right', nextDirection: 'right' }; |
|
document.getElementById('pacman').style.left = `${pacman.x * CELL_SIZE}px`; |
|
document.getElementById('pacman').style.top = `${pacman.y * CELL_SIZE}px`; |
|
document.getElementById('pacman').style.transform = 'rotate(0deg)'; |
|
|
|
ghosts.forEach(ghost => { |
|
if (ghost.id === 'blinky' || ghost.id === 'pinky') { |
|
ghost.x = ghost.id === 'blinky' ? 13 : 14; |
|
ghost.y = 11; |
|
} else { |
|
ghost.x = ghost.id === 'inky' ? 13 : 14; |
|
ghost.y = 14; |
|
} |
|
|
|
ghost.direction = 'up'; |
|
ghost.isScared = false; |
|
ghost.isEaten = false; |
|
ghost.element.classList.remove('bg-blue-500', 'bg-gray-400', 'bg-white'); |
|
ghost.element.classList.add(`bg-${ghost.id === 'blinky' ? 'red' : ghost.id === 'pinky' ? 'pink' : ghost.id === 'inky' ? 'cyan' : 'orange'}-500`); |
|
ghost.element.style.left = `${ghost.x * CELL_SIZE}px`; |
|
ghost.element.style.top = `${ghost.y * CELL_SIZE}px`; |
|
}); |
|
|
|
|
|
scaredGhosts = false; |
|
if (scaredTimer) clearTimeout(scaredTimer); |
|
pacmanBoost = false; |
|
if (pacmanBoostTimer) clearTimeout(pacmanBoostTimer); |
|
} |
|
|
|
|
|
function gameOver() { |
|
gameRunning = false; |
|
document.getElementById('final-score').textContent = score; |
|
document.getElementById('game-over').classList.remove('hidden'); |
|
document.getElementById('restart-btn').classList.remove('hidden'); |
|
if (fruitTimer) clearTimeout(fruitTimer); |
|
} |
|
|
|
|
|
function updateDisplay() { |
|
|
|
const pacmanElement = document.getElementById('pacman'); |
|
pacmanElement.style.clipPath = 'polygon(50% 50%, 100% 0%, 100% 100%)'; |
|
|
|
|
|
ghosts.forEach(ghost => { |
|
if (ghost.isScared) { |
|
|
|
const remainingScaredTime = scaredTimer ? parseInt((scaredTimer._idleTimeout - scaredTimer._idleStart) / 1000) : 0; |
|
if (remainingScaredTime <= 3 && Date.now() % 200 < 100) { |
|
ghost.element.classList.remove('bg-blue-500'); |
|
ghost.element.classList.add('bg-white'); |
|
} else { |
|
ghost.element.classList.remove('bg-white'); |
|
ghost.element.classList.add('bg-blue-500'); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
function startGame() { |
|
document.getElementById('start-screen').classList.add('hidden'); |
|
initGame(); |
|
} |
|
|
|
|
|
document.addEventListener('keydown', (e) => { |
|
if (e.key === 'Enter' && !gameRunning && !document.getElementById('start-screen').classList.contains('hidden')) { |
|
startGame(); |
|
} |
|
|
|
if (!gameRunning) return; |
|
|
|
switch (e.key) { |
|
case 'ArrowLeft': |
|
pacman.nextDirection = 'left'; |
|
break; |
|
case 'ArrowRight': |
|
pacman.nextDirection = 'right'; |
|
break; |
|
case 'ArrowUp': |
|
pacman.nextDirection = 'up'; |
|
break; |
|
case 'ArrowDown': |
|
pacman.nextDirection = 'down'; |
|
break; |
|
} |
|
}); |
|
|
|
document.getElementById('restart-btn').addEventListener('click', initGame); |
|
document.getElementById('game-over-restart').addEventListener('click', () => { |
|
document.getElementById('game-over').classList.add('hidden'); |
|
initGame(); |
|
}); |
|
|
|
|
|
document.getElementById('start-screen').addEventListener('click', startGame); |
|
}); |
|
</script> |
|
<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> |
|
</html> |