Initial commit
This commit is contained in:
@@ -0,0 +1,535 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>Maze Chomper</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html, body { width: 100%; height: 100%; overflow: hidden; background: #000; touch-action: none; font-family: Arial, sans-serif; }
|
||||
canvas { display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="game"></canvas>
|
||||
<script>
|
||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
let audioCtx = null;
|
||||
let musicEnabled = true;
|
||||
let sfxEnabled = true;
|
||||
let musicPlaying = false;
|
||||
|
||||
function initAudio() {
|
||||
if (!audioCtx) audioCtx = new AudioContext();
|
||||
if (audioCtx.state === 'suspended') audioCtx.resume();
|
||||
}
|
||||
|
||||
// Classic arcade melody
|
||||
const melody = [
|
||||
{n: 523, d: 0.15}, {n: 587, d: 0.15}, {n: 659, d: 0.15}, {n: 784, d: 0.3},
|
||||
{n: 659, d: 0.15}, {n: 587, d: 0.15}, {n: 523, d: 0.3},
|
||||
{n: 392, d: 0.15}, {n: 440, d: 0.15}, {n: 494, d: 0.15}, {n: 523, d: 0.3},
|
||||
{n: 494, d: 0.15}, {n: 440, d: 0.15}, {n: 392, d: 0.3}, {n: 0, d: 0.15}
|
||||
];
|
||||
|
||||
const bass = [
|
||||
{n: 131, d: 0.3}, {n: 165, d: 0.3}, {n: 196, d: 0.3}, {n: 165, d: 0.3},
|
||||
{n: 98, d: 0.3}, {n: 110, d: 0.3}, {n: 131, d: 0.3}, {n: 165, d: 0.3}
|
||||
];
|
||||
|
||||
let melodyIdx = 0, bassIdx = 0, nextMelody = 0, nextBass = 0;
|
||||
|
||||
function playTone(freq, dur, type = 'square', vol = 0.1) {
|
||||
if (!audioCtx || !musicEnabled || freq === 0) return;
|
||||
const osc = audioCtx.createOscillator();
|
||||
const gain = audioCtx.createGain();
|
||||
osc.type = type;
|
||||
osc.frequency.value = freq;
|
||||
gain.gain.setValueAtTime(vol, audioCtx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + dur * 0.9);
|
||||
osc.connect(gain);
|
||||
gain.connect(audioCtx.destination);
|
||||
osc.start();
|
||||
osc.stop(audioCtx.currentTime + dur);
|
||||
}
|
||||
|
||||
function playSfx(type) {
|
||||
if (!audioCtx || !sfxEnabled) return;
|
||||
const osc = audioCtx.createOscillator();
|
||||
const gain = audioCtx.createGain();
|
||||
if (type === 'chomp') {
|
||||
osc.frequency.setValueAtTime(400, audioCtx.currentTime);
|
||||
osc.frequency.setValueAtTime(300, audioCtx.currentTime + 0.05);
|
||||
gain.gain.setValueAtTime(0.12, audioCtx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1);
|
||||
} else if (type === 'power') {
|
||||
osc.frequency.setValueAtTime(523, audioCtx.currentTime);
|
||||
osc.frequency.setValueAtTime(659, audioCtx.currentTime + 0.1);
|
||||
osc.frequency.setValueAtTime(784, audioCtx.currentTime + 0.2);
|
||||
gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
|
||||
} else if (type === 'ghost') {
|
||||
osc.frequency.value = 800;
|
||||
gain.gain.setValueAtTime(0.15, audioCtx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2);
|
||||
} else if (type === 'die') {
|
||||
osc.frequency.setValueAtTime(400, audioCtx.currentTime);
|
||||
osc.frequency.exponentialRampToValueAtTime(100, audioCtx.currentTime + 0.4);
|
||||
gain.gain.setValueAtTime(0.25, audioCtx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.4);
|
||||
osc.type = 'sawtooth';
|
||||
}
|
||||
osc.connect(gain);
|
||||
gain.connect(audioCtx.destination);
|
||||
osc.start();
|
||||
osc.stop(audioCtx.currentTime + 0.5);
|
||||
}
|
||||
|
||||
function updateMusic() {
|
||||
if (!audioCtx || !musicEnabled || !musicPlaying) return;
|
||||
const now = audioCtx.currentTime;
|
||||
if (now >= nextMelody) {
|
||||
const note = melody[melodyIdx];
|
||||
playTone(note.n, note.d, 'square', 0.07);
|
||||
nextMelody = now + note.d;
|
||||
melodyIdx = (melodyIdx + 1) % melody.length;
|
||||
}
|
||||
if (now >= nextBass) {
|
||||
const note = bass[bassIdx];
|
||||
playTone(note.n, note.d, 'triangle', 0.1);
|
||||
nextBass = now + note.d;
|
||||
bassIdx = (bassIdx + 1) % bass.length;
|
||||
}
|
||||
}
|
||||
|
||||
function startMusic() {
|
||||
if (!musicPlaying && musicEnabled) {
|
||||
initAudio();
|
||||
musicPlaying = true;
|
||||
nextMelody = audioCtx.currentTime;
|
||||
nextBass = audioCtx.currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
const canvas = document.getElementById('game');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let W, H, safeTop, safeBottom;
|
||||
|
||||
function resize() {
|
||||
W = window.innerWidth;
|
||||
H = window.innerHeight;
|
||||
canvas.width = W;
|
||||
canvas.height = H;
|
||||
safeTop = H * 0.1;
|
||||
safeBottom = H * 0.9;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
// Simple maze layout (0 = path, 1 = wall)
|
||||
const MAZE = [
|
||||
[1,1,1,1,1,1,1,1,1,1,1,1,1],
|
||||
[1,0,0,0,0,0,1,0,0,0,0,0,1],
|
||||
[1,0,1,1,1,0,1,0,1,1,1,0,1],
|
||||
[1,0,0,0,0,0,0,0,0,0,0,0,1],
|
||||
[1,0,1,1,1,0,1,0,1,1,1,0,1],
|
||||
[1,0,0,0,0,0,1,0,0,0,0,0,1],
|
||||
[1,1,1,0,1,1,1,1,1,0,1,1,1],
|
||||
[1,0,0,0,0,0,0,0,0,0,0,0,1],
|
||||
[1,0,1,1,1,0,1,0,1,1,1,0,1],
|
||||
[1,0,0,0,0,0,1,0,0,0,0,0,1],
|
||||
[1,1,1,1,1,1,1,1,1,1,1,1,1]
|
||||
];
|
||||
|
||||
const ROWS = MAZE.length;
|
||||
const COLS = MAZE[0].length;
|
||||
|
||||
let cellSize, mazeX, mazeY;
|
||||
let player = { x: 1, y: 1, dir: { x: 0, y: 0 }, nextDir: { x: 0, y: 0 }, mouthOpen: 0 };
|
||||
let ghosts = [];
|
||||
let dots = [];
|
||||
let powerPellets = [];
|
||||
let score = 0;
|
||||
let lives = 3;
|
||||
let level = 1;
|
||||
let gameOver = false;
|
||||
let gameRunning = false;
|
||||
let powerMode = false;
|
||||
let powerTimer = 0;
|
||||
|
||||
function calcMaze() {
|
||||
const availH = safeBottom - safeTop - 60;
|
||||
const availW = W - 40;
|
||||
cellSize = Math.min(availW / COLS, availH / ROWS);
|
||||
mazeX = (W - cellSize * COLS) / 2;
|
||||
mazeY = safeTop + 40 + (availH - cellSize * ROWS) / 2;
|
||||
}
|
||||
|
||||
function initDots() {
|
||||
dots = [];
|
||||
powerPellets = [];
|
||||
for (let r = 0; r < ROWS; r++) {
|
||||
for (let c = 0; c < COLS; c++) {
|
||||
if (MAZE[r][c] === 0) {
|
||||
// Power pellets in corners
|
||||
if ((r === 1 || r === ROWS - 2) && (c === 1 || c === COLS - 2)) {
|
||||
powerPellets.push({ x: c, y: r });
|
||||
} else {
|
||||
dots.push({ x: c, y: r });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initGhosts() {
|
||||
ghosts = [
|
||||
{ x: 6, y: 5, dir: { x: 0, y: -1 }, color: '#ff0000', scared: false, speed: 0.03 },
|
||||
{ x: 6, y: 5, dir: { x: 1, y: 0 }, color: '#00ffff', scared: false, speed: 0.025 },
|
||||
{ x: 6, y: 5, dir: { x: -1, y: 0 }, color: '#ffb8ff', scared: false, speed: 0.02 }
|
||||
];
|
||||
}
|
||||
|
||||
function init() {
|
||||
calcMaze();
|
||||
player.x = 1;
|
||||
player.y = 1;
|
||||
player.dir = { x: 0, y: 0 };
|
||||
player.nextDir = { x: 0, y: 0 };
|
||||
initDots();
|
||||
initGhosts();
|
||||
score = 0;
|
||||
lives = 3;
|
||||
level = 1;
|
||||
powerMode = false;
|
||||
powerTimer = 0;
|
||||
gameOver = false;
|
||||
gameRunning = true;
|
||||
startMusic();
|
||||
}
|
||||
|
||||
function canMove(x, y) {
|
||||
const col = Math.floor(x);
|
||||
const row = Math.floor(y);
|
||||
if (row < 0 || row >= ROWS || col < 0 || col >= COLS) return false;
|
||||
return MAZE[row][col] === 0;
|
||||
}
|
||||
|
||||
function setDirection(dx, dy) {
|
||||
player.nextDir = { x: dx, y: dy };
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
initAudio();
|
||||
if (e.key === 'ArrowLeft' || e.key === 'a') setDirection(-1, 0);
|
||||
if (e.key === 'ArrowRight' || e.key === 'd') setDirection(1, 0);
|
||||
if (e.key === 'ArrowUp' || e.key === 'w') setDirection(0, -1);
|
||||
if (e.key === 'ArrowDown' || e.key === 's') setDirection(0, 1);
|
||||
if ((e.key === ' ' || e.key === 'Enter') && gameOver) init();
|
||||
});
|
||||
|
||||
let touchStartX = 0, touchStartY = 0;
|
||||
canvas.addEventListener('touchstart', e => {
|
||||
e.preventDefault();
|
||||
initAudio();
|
||||
if (gameOver) { init(); return; }
|
||||
touchStartX = e.touches[0].clientX;
|
||||
touchStartY = e.touches[0].clientY;
|
||||
});
|
||||
|
||||
canvas.addEventListener('touchend', e => {
|
||||
const dx = e.changedTouches[0].clientX - touchStartX;
|
||||
const dy = e.changedTouches[0].clientY - touchStartY;
|
||||
if (Math.abs(dx) > Math.abs(dy)) {
|
||||
setDirection(dx > 0 ? 1 : -1, 0);
|
||||
} else {
|
||||
setDirection(0, dy > 0 ? 1 : -1);
|
||||
}
|
||||
});
|
||||
|
||||
canvas.addEventListener('click', e => {
|
||||
initAudio();
|
||||
if (gameOver) init();
|
||||
});
|
||||
|
||||
function update() {
|
||||
if (!gameRunning || gameOver) return;
|
||||
|
||||
const speed = 0.06;
|
||||
|
||||
// Try to turn
|
||||
const testX = player.x + player.nextDir.x * speed;
|
||||
const testY = player.y + player.nextDir.y * speed;
|
||||
if (canMove(testX + 0.5, testY + 0.5)) {
|
||||
player.dir = { ...player.nextDir };
|
||||
}
|
||||
|
||||
// Move player
|
||||
const newX = player.x + player.dir.x * speed;
|
||||
const newY = player.y + player.dir.y * speed;
|
||||
if (canMove(newX + 0.5, newY + 0.5)) {
|
||||
player.x = newX;
|
||||
player.y = newY;
|
||||
}
|
||||
|
||||
// Animate mouth
|
||||
player.mouthOpen = (player.mouthOpen + 0.2) % (Math.PI * 2);
|
||||
|
||||
// Collect dots
|
||||
for (let i = dots.length - 1; i >= 0; i--) {
|
||||
const d = dots[i];
|
||||
if (Math.abs(player.x + 0.5 - d.x - 0.5) < 0.5 && Math.abs(player.y + 0.5 - d.y - 0.5) < 0.5) {
|
||||
dots.splice(i, 1);
|
||||
score += 10;
|
||||
playSfx('chomp');
|
||||
}
|
||||
}
|
||||
|
||||
// Collect power pellets
|
||||
for (let i = powerPellets.length - 1; i >= 0; i--) {
|
||||
const p = powerPellets[i];
|
||||
if (Math.abs(player.x + 0.5 - p.x - 0.5) < 0.5 && Math.abs(player.y + 0.5 - p.y - 0.5) < 0.5) {
|
||||
powerPellets.splice(i, 1);
|
||||
score += 50;
|
||||
powerMode = true;
|
||||
powerTimer = 300;
|
||||
ghosts.forEach(g => g.scared = true);
|
||||
playSfx('power');
|
||||
}
|
||||
}
|
||||
|
||||
// Power mode timer
|
||||
if (powerMode) {
|
||||
powerTimer--;
|
||||
if (powerTimer <= 0) {
|
||||
powerMode = false;
|
||||
ghosts.forEach(g => g.scared = false);
|
||||
}
|
||||
}
|
||||
|
||||
// Move ghosts
|
||||
ghosts.forEach(ghost => {
|
||||
// Simple AI: mostly random, occasionally chase
|
||||
if (Math.random() < 0.02) {
|
||||
const dirs = [{ x: 1, y: 0 }, { x: -1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: -1 }];
|
||||
const validDirs = dirs.filter(d =>
|
||||
canMove(ghost.x + d.x * 0.5 + 0.5, ghost.y + d.y * 0.5 + 0.5)
|
||||
);
|
||||
if (validDirs.length > 0) {
|
||||
ghost.dir = validDirs[Math.floor(Math.random() * validDirs.length)];
|
||||
}
|
||||
}
|
||||
|
||||
const gSpeed = ghost.scared ? ghost.speed * 0.5 : ghost.speed;
|
||||
const newGX = ghost.x + ghost.dir.x * gSpeed;
|
||||
const newGY = ghost.y + ghost.dir.y * gSpeed;
|
||||
|
||||
if (canMove(newGX + 0.5, newGY + 0.5)) {
|
||||
ghost.x = newGX;
|
||||
ghost.y = newGY;
|
||||
} else {
|
||||
// Turn randomly
|
||||
const dirs = [{ x: 1, y: 0 }, { x: -1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: -1 }];
|
||||
const validDirs = dirs.filter(d =>
|
||||
canMove(ghost.x + d.x * 0.5 + 0.5, ghost.y + d.y * 0.5 + 0.5)
|
||||
);
|
||||
if (validDirs.length > 0) {
|
||||
ghost.dir = validDirs[Math.floor(Math.random() * validDirs.length)];
|
||||
}
|
||||
}
|
||||
|
||||
// Collision with player
|
||||
const dx = ghost.x - player.x;
|
||||
const dy = ghost.y - player.y;
|
||||
if (Math.sqrt(dx * dx + dy * dy) < 0.7) {
|
||||
if (ghost.scared) {
|
||||
// Eat ghost
|
||||
ghost.x = 6;
|
||||
ghost.y = 5;
|
||||
ghost.scared = false;
|
||||
score += 200;
|
||||
playSfx('ghost');
|
||||
} else {
|
||||
// Die
|
||||
lives--;
|
||||
playSfx('die');
|
||||
if (lives <= 0) {
|
||||
gameOver = true;
|
||||
gameRunning = false;
|
||||
musicPlaying = false;
|
||||
} else {
|
||||
// Reset positions
|
||||
player.x = 1;
|
||||
player.y = 1;
|
||||
player.dir = { x: 0, y: 0 };
|
||||
initGhosts();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Level complete
|
||||
if (dots.length === 0 && powerPellets.length === 0) {
|
||||
level++;
|
||||
initDots();
|
||||
initGhosts();
|
||||
player.x = 1;
|
||||
player.y = 1;
|
||||
player.dir = { x: 0, y: 0 };
|
||||
// Ghosts get faster
|
||||
ghosts.forEach(g => g.speed += 0.005);
|
||||
}
|
||||
|
||||
updateMusic();
|
||||
}
|
||||
|
||||
function draw() {
|
||||
calcMaze();
|
||||
|
||||
// Background
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
|
||||
// Safe zones
|
||||
ctx.fillStyle = '#111';
|
||||
ctx.fillRect(0, 0, W, safeTop);
|
||||
ctx.fillRect(0, safeBottom, W, H - safeBottom);
|
||||
|
||||
// Header
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = 'bold 22px Arial';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(`Score: ${score}`, 20, 35);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(`Level ${level}`, W / 2, 35);
|
||||
ctx.textAlign = 'right';
|
||||
ctx.fillText(`Lives: ${'●'.repeat(lives)}`, W - 20, 35);
|
||||
|
||||
// Draw maze
|
||||
for (let r = 0; r < ROWS; r++) {
|
||||
for (let c = 0; c < COLS; c++) {
|
||||
const x = mazeX + c * cellSize;
|
||||
const y = mazeY + r * cellSize;
|
||||
if (MAZE[r][c] === 1) {
|
||||
ctx.fillStyle = '#00f';
|
||||
ctx.fillRect(x, y, cellSize, cellSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw dots
|
||||
ctx.fillStyle = '#ffb8ae';
|
||||
for (const d of dots) {
|
||||
const x = mazeX + (d.x + 0.5) * cellSize;
|
||||
const y = mazeY + (d.y + 0.5) * cellSize;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, cellSize * 0.1, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw power pellets
|
||||
ctx.fillStyle = '#ffb8ae';
|
||||
for (const p of powerPellets) {
|
||||
const x = mazeX + (p.x + 0.5) * cellSize;
|
||||
const y = mazeY + (p.y + 0.5) * cellSize;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, cellSize * 0.25, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw ghosts
|
||||
for (const ghost of ghosts) {
|
||||
const x = mazeX + (ghost.x + 0.5) * cellSize;
|
||||
const y = mazeY + (ghost.y + 0.5) * cellSize;
|
||||
const size = cellSize * 0.4;
|
||||
|
||||
ctx.fillStyle = ghost.scared ? '#0000ff' : ghost.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y - size * 0.2, size, Math.PI, 0);
|
||||
ctx.lineTo(x + size, y + size * 0.5);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const wx = x + size - (i + 0.5) * (size * 2 / 3);
|
||||
ctx.lineTo(wx, y + size * 0.2);
|
||||
ctx.lineTo(wx - size / 3, y + size * 0.5);
|
||||
}
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// Eyes
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.beginPath();
|
||||
ctx.arc(x - size * 0.3, y - size * 0.3, size * 0.2, 0, Math.PI * 2);
|
||||
ctx.arc(x + size * 0.3, y - size * 0.3, size * 0.2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = ghost.scared ? '#fff' : '#00f';
|
||||
ctx.beginPath();
|
||||
ctx.arc(x - size * 0.3, y - size * 0.3, size * 0.1, 0, Math.PI * 2);
|
||||
ctx.arc(x + size * 0.3, y - size * 0.3, size * 0.1, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw player (Pac-Man)
|
||||
const px = mazeX + (player.x + 0.5) * cellSize;
|
||||
const py = mazeY + (player.y + 0.5) * cellSize;
|
||||
const pSize = cellSize * 0.4;
|
||||
const mouthAngle = Math.abs(Math.sin(player.mouthOpen)) * 0.5;
|
||||
|
||||
let angle = 0;
|
||||
if (player.dir.x === 1) angle = 0;
|
||||
else if (player.dir.x === -1) angle = Math.PI;
|
||||
else if (player.dir.y === 1) angle = Math.PI / 2;
|
||||
else if (player.dir.y === -1) angle = -Math.PI / 2;
|
||||
|
||||
ctx.fillStyle = '#ff0';
|
||||
ctx.beginPath();
|
||||
ctx.arc(px, py, pSize, angle + mouthAngle, angle + Math.PI * 2 - mouthAngle);
|
||||
ctx.lineTo(px, py);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// Controls hint
|
||||
ctx.fillStyle = '#666';
|
||||
ctx.font = '14px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('Swipe or Arrow Keys to move', W / 2, safeBottom + 25);
|
||||
|
||||
if (gameOver) {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.85)';
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
ctx.fillStyle = '#ff0';
|
||||
ctx.font = 'bold 40px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('GAME OVER', W / 2, H / 2 - 50);
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = '24px Arial';
|
||||
ctx.fillText(`Final Score: ${score}`, W / 2, H / 2);
|
||||
|
||||
ctx.fillStyle = '#ff0';
|
||||
ctx.beginPath();
|
||||
ctx.roundRect(W / 2 - 100, H / 2 + 30, 200, 50, 10);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.font = 'bold 18px Arial';
|
||||
ctx.fillText('TAP TO PLAY AGAIN', W / 2, H / 2 + 62);
|
||||
}
|
||||
}
|
||||
|
||||
function gameLoop() {
|
||||
update();
|
||||
draw();
|
||||
requestAnimationFrame(gameLoop);
|
||||
}
|
||||
|
||||
window.gameScore = 0;
|
||||
Object.defineProperty(window, 'gameScore', { get: () => score });
|
||||
window.pauseGame = () => { gameRunning = false; musicPlaying = false; };
|
||||
window.resumeGame = () => { if (!gameOver) { gameRunning = true; startMusic(); } };
|
||||
window.setMusicEnabled = (v) => { musicEnabled = v; if (!v) musicPlaying = false; };
|
||||
window.setSfxEnabled = (v) => { sfxEnabled = v; };
|
||||
|
||||
init();
|
||||
gameLoop();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user