WEBLEB
Home
Editor
Login
Pro
English
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Mini Pac-Man Game HTML Canvas JavaScript
16
iroger7
Open In Editor
Publish Your Code
Recommended
24 June 2025
Digital Agency HTML Template | Tailwind CSS
11 August 2025
HTML Message Animation Container
12 October 2025
CSS Loading Animation HTML Structure
HTML
Copy
Mini Pac‑Man — Fixed Lower Area
Score:
0
Lives:
3
Start
Mini Pac‑Man
Use arrow keys to move. Eat all dots to win. Avoid ghosts.
Play
CSS
Copy
/* Replace with your CSS Code (Leave empty if not needed) */
JS
Copy
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>Mini Pac‑Man — Demo</title> <style> :root{ --bg:#000; --wall:#0d4f66; --dot:#ffd54f; --pac:#ffeb3b; --ghost:#ff6b6b; --text:#fff; } html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,'Helvetica Neue',Arial;background:#111;color:var(--text)} .wrap{min-height:100%;display:flex;align-items:center;justify-content:center;padding:18px;box-sizing:border-box} .game{ width:560px;height:620px;background:linear-gradient(#071428,#001021);border-radius:10px;box-shadow:0 10px 30px rgba(0,0,0,0.6);position:relative;overflow:hidden; display:flex;flex-direction:column;align-items:center;padding:12px; } canvas{background:var(--bg);border-radius:6px} .ui{width:100%;display:flex;justify-content:space-between;align-items:center;color:var(--text);padding:6px 10px} .panel{background:rgba(255,255,255,0.04);padding:8px 12px;border-radius:8px} button{background:#1976d2;color:white;border:none;padding:8px 12px;border-radius:8px;font-weight:700;cursor:pointer} .overlay{ position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:auto; } .panelBig{background:rgba(0,0,0,0.7);padding:18px;border-radius:12px;color:var(--text);text-align:center} @media (max-width:640px){ .game{width:360px;height:520px} canvas{width:320px;height:320px} } </style> </head> <body> <div class="wrap"> <div class="game" id="gameRoot" role="application" aria-label="Mini Pac-Man game"> <div class="ui"> <div class="panel">Score: <span id="score">0</span></div> <div class="panel">Lives: <span id="lives">3</span></div> <div><button id="startBtn">Start</button></div> </div> <canvas id="canvas" width="560" height="560" aria-hidden="false"></canvas> <div class="overlay" id="overlay" style="display:flex"> <div class="panelBig"> <h2 style="margin:0 0 8px 0">Mini Pac‑Man</h2> <p style="margin:0 0 12px 0">Use arrow keys to move. Eat all dots to win. Avoid ghosts.</p> <button id="overlayStart">Play</button> </div> </div> </div> </div> <script> /* Mini Pac‑Man - Single HTML file for classroom/demo use. - Simplified mechanics: grid-based movement, dots, 2 ghosts, basic collision. - Expandable: add power pellets, levels, sound, more ghosts. */ (function(){ const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const startBtn = document.getElementById('startBtn'); const overlay = document.getElementById('overlay'); const overlayStart = document.getElementById('overlayStart'); const scoreLabel = document.getElementById('score'); const livesLabel = document.getElementById('lives'); // Grid settings const COLS = 28; // classic Pac-Man uses 28x31; we'll use 28x28 for square canvas const ROWS = 28; const TILE = Math.floor(canvas.width / COLS); const W = TILE * COLS; const H = TILE * ROWS; canvas.width = W; canvas.height = H; // Colors const COLORS = { wall: '#0d4f66', floor: '#071428', dot: '#ffd54f', pac: '#ffeb3b', ghost: '#ff6b6b', frightened: '#7fd3ff' }; // Game state let map = []; // 2D array: 0=floor,1=wall,2=dot let pac = { x: 14, y: 20, dir: {x:0,y:0}, nextDir: {x:0,y:0}, speed:1 }; let ghosts = []; let score = 0; let lives = 3; let running = false; let lastTime = 0; // Build a simple maze layout (0 floor, 1 wall). This is a small hand-crafted maze pattern. const raw = [ "1111111111111111111111111111", "1000000000110000000000000001", "1011111110110111111110111101", "1020000010000001000000010201", "1010111011111101111101010101", "1010111010000101000101010101", "1000000010110101010100000001", "1011111010110101010111111101", "1000000010000000000100000001", "1011111011111101111101111101", "1010000010000101000101000101", "1010111110110101010101110101", "1010000010000101000100000101", "1011111010111101111101111101", "1000000010000000000100000001", "1011111010110111110111111101", "1000000010110000000100000001", "1011111010111111110111111101", "1000000000000000000000000001", "1011111111111111111111111101", "1000000000000000000000000001", "1111111111111111111111111111", "1000000000000000000000000001", "1011111111111111111111111101", "1000000000000000000000000001", "1011111111111111111111111101", "1000000000000000000000000001", "1111111111111111111111111111" ]; function initMap(){ map = []; for (let y=0;y<ROWS;y++){ const row = []; const str = raw[y] || raw[raw.length-1]; for (let x=0;x<COLS;x++){ const ch = str[x] || '1'; if (ch === '1') row.push(1); // wall else if (ch === '0') row.push(2); // dot else if (ch === '2') row.push(0); // empty space (useful for tunnels/spawn) else row.push(1); } map.push(row); } } function resetEntities(){ pac.x = 14; pac.y = 20; pac.dir = {x:0,y:0}; pac.nextDir = {x:0,y:0}; ghosts = [ { x: 13, y: 11, dir:{x:0,y:0}, color:'#ff6b6b', mode:'chase' }, { x: 14, y: 11, dir:{x:0,y:0}, color:'#6b8cff', mode:'chase' } ]; } function startGame(){ initMap(); resetEntities(); score = 0; lives = 3; running = true; overlay.style.display = 'none'; scoreLabel.textContent = score; livesLabel.textContent = lives; lastTime = performance.now(); requestAnimationFrame(loop); } function endRound(){ lives--; livesLabel.textContent = lives; if (lives <= 0){ running = false; overlay.querySelector('.panelBig').innerHTML = '<h2 style="margin:0 0 8px 0">Game Over</h2><p style="margin:0 0 12px 0">Score: '+score+'</p><button id="playAgain">Play Again</button>'; overlay.style.display = 'flex'; document.getElementById('playAgain').addEventListener('click', ()=>startGame()); } else { resetEntities(); } } // Input window.addEventListener('keydown', (e)=>{ if (!running && (e.key === 'Enter' || e.key === ' ')) startGame(); const dir = keyToDir(e.key); if (dir) { pac.nextDir = dir; e.preventDefault(); } }); function keyToDir(k){ if (k === 'ArrowUp') return {x:0,y:-1}; if (k === 'ArrowDown') return {x:0,y:1}; if (k === 'ArrowLeft') return {x:-1,y:0}; if (k === 'ArrowRight') return {x:1,y:0}; return null; } // Movement helpers function canMoveTo(x,y){ if (y<0 || y>=ROWS || x<0 || x>=COLS) return false; return map[y][x] !== 1; } function update(dt){ // Pac-Man movement: grid-based with simple interpolation // Try to change direction if possible const nextX = pac.x + pac.nextDir.x; const nextY = pac.y + pac.nextDir.y; if (canMoveTo(nextX, nextY)){ pac.dir = pac.nextDir; } const targetX = pac.x + pac.dir.x; const targetY = pac.y + pac.dir.y; if (canMoveTo(targetX, targetY)){ pac.x = targetX; pac.y = targetY; } else { // blocked, stop pac.dir = {x:0,y:0}; } // collect dots if (map[pac.y][pac.x] === 2){ map[pac.y][pac.x] = 0; score += 10; scoreLabel.textContent = score; // check win: any dots left? if (!map.some(row => row.includes(2))){ running = false; overlay.querySelector('.panelBig').innerHTML = '<h2 style="margin:0 0 8px 0">You Win!</h2><p style="margin:0 0 12px 0">Score: '+score+'</p><button id="playAgain">Play Again</button>'; overlay.style.display = 'flex'; document.getElementById('playAgain').addEventListener('click', ()=>startGame()); } } // simple ghost AI: random valid direction, biased toward Pac-Man for (let g of ghosts){ if (Math.random() < 0.25){ // occasionally choose a new direction toward Pac const dx = pac.x - g.x; const dy = pac.y - g.y; let dir; if (Math.abs(dx) > Math.abs(dy)) dir = {x: Math.sign(dx), y:0}; else dir = {x:0, y: Math.sign(dy)}; const nx = g.x + dir.x, ny = g.y + dir.y; if (canMoveTo(nx,ny)) g.dir = dir; else { // pick random valid direction const opts = [{x:1,y:0},{x:-1,y:0},{x:0,y:1},{x:0,y:-1}].filter(d=>canMoveTo(g.x+d.x,g.y+d.y)); if (opts.length) g.dir = opts[Math.floor(Math.random()*opts.length)]; } } // move const gx = g.x + g.dir.x, gy = g.y + g.dir.y; if (canMoveTo(gx,gy)) { g.x = gx; g.y = gy; } } // collisions for (let g of ghosts){ if (g.x === pac.x && g.y === pac.y){ endRound(); break; } } } function draw(){ // background ctx.fillStyle = COLORS.floor; ctx.fillRect(0,0,W,H); // draw map for (let y=0;y<ROWS;y++){ for (let x=0;x<COLS;x++){ const v = map[y][x]; const px = x * TILE, py = y * TILE; if (v === 1){ // wall ctx.fillStyle = COLORS.wall; ctx.fillRect(px, py, TILE, TILE); // small bevel ctx.fillStyle = shadeColor(COLORS.wall, -10); ctx.fillRect(px+2, py+2, TILE-4, TILE-4); } else { // dot if (v === 2){ ctx.fillStyle = COLORS.dot; const r = Math.max(2, TILE * 0.12); ctx.beginPath(); ctx.arc(px + TILE/2, py + TILE/2, r, 0, Math.PI*2); ctx.fill(); } } } } // draw Pac-Man (simple circle with mouth indicating direction) const cx = pac.x * TILE + TILE/2; const cy = pac.y * TILE + TILE/2; ctx.fillStyle = COLORS.pac; // mouth angle based on dir let angle = 0.25; let start = 0.25*Math.PI, end = -0.25*Math.PI; if (pac.dir.x === 1) { start = 0.25*Math.PI; end = -0.25*Math.PI; } if (pac.dir.x === -1) { start = Math.PI+0.25*Math.PI; end = Math.PI-0.25*Math.PI; } if (pac.dir.y === -1) { start = -0.25*Math.PI; end = -0.75*Math.PI; } if (pac.dir.y === 1) { start = 0.75*Math.PI; end = 0.25*Math.PI; } // if stationary, small chomping if (pac.dir.x===0 && pac.dir.y===0){ start = 0.25*Math.PI; end = -0.25*Math.PI; } ctx.beginPath(); ctx.moveTo(cx,cy); ctx.arc(cx,cy, TILE*0.42, start, end, false); ctx.closePath(); ctx.fill(); // draw ghosts for (let g of ghosts){ const gx = g.x * TILE + TILE/2; const gy = g.y * TILE + TILE/2; const r = TILE*0.42; // body ctx.beginPath(); ctx.fillStyle = g.color; ctx.arc(gx, gy, r, Math.PI, 0, false); ctx.rect(gx - r, gy, r*2, r); ctx.fill(); // eyes ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(gx - r*0.3, gy - r*0.15, r*0.18, 0, Math.PI*2); ctx.arc(gx + r*0.3, gy - r*0.15, r*0.18, 0, Math.PI*2); ctx.fill(); ctx.fillStyle = '#000'; ctx.beginPath(); ctx.arc(gx - r*0.3, gy - r*0.15, r*0.08, 0, Math.PI*2); ctx.arc(gx + r*0.3, gy - r*0.15, r*0.08, 0, Math.PI*2); ctx.fill(); } } function loop(now){ const dt = Math.min(200, now - lastTime); if (running){ // update at a fixed-ish tick rate: move once every 140ms // accumulate time-based ticks tickAccumulator += dt; while (tickAccumulator > tickInterval){ update(tickInterval); tickAccumulator -= tickInterval; } } draw(); lastTime = now; requestAnimationFrame(loop); } // simple shading helper function shadeColor(col, percent) { const num = parseInt(col.replace('#',''),16); const r = Math.min(255, Math.max(0, (num>>16) + percent)); const g = Math.min(255, Math.max(0, ((num>>8)&0x00FF) + percent)); const b = Math.min(255, Math.max(0, (num&0x0000FF) + percent)); return '#' + ( (1<<24) + (r<<16) + (g<<8) + b ).toString(16).slice(1); } // Timing for grid ticks let tickAccumulator = 0; const tickInterval = 140; // ms per grid movement // Start/pause controls startBtn.addEventListener('click', ()=>{ if (!running) startGame(); }); overlayStart.addEventListener('click', startGame); // Initialize initMap(); resetEntities(); draw(); // Accessibility: allow clicking on canvas to move (simple direction control) canvas.addEventListener('click', (e)=>{ const rect = canvas.getBoundingClientRect(); const mx = e.clientX - rect.left; const my = e.clientY - rect.top; const dx = mx - (pac.x * TILE + TILE/2); const dy = my - (pac