document.addEventListener('DOMContentLoaded', () => { const canvas = document.getElementById('maze-canvas'); const ctx = canvas.getContext('2d'); const timeDisplay = document.getElementById('time'); const movesDisplay = document.getElementById('moves'); const difficultySelect = document.getElementById('difficulty'); const startBtn = document.getElementById('start-btn'); const upBtn = document.getElementById('up-btn'); const downBtn = document.getElementById('down-btn'); const leftBtn = document.getElementById('left-btn'); const rightBtn = document.getElementById('right-btn'); // Set canvas size function resizeCanvas() { const container = document.getElementById('maze-container'); const size = Math.min(container.offsetWidth, container.offsetHeight); canvas.width = size; canvas.height = size; } // Game variables let maze = []; let cellSize = 0; let orientationEnabled = false; let ufo = { x: 0, y: 0 }; let exit = { x: 0, y: 0 }; let moves = 0; let time = 0; let timer = null; let gameRunning = false; let mazeSize = 25; // Handle device orientation function handleOrientation(event) { if (!gameRunning) return; const tiltThreshold = 15; // degrees const beta = event.beta; // front-to-back tilt const gamma = event.gamma; // left-to-right tilt if (beta > tiltThreshold) { moveUfo(0, 1); // tilt forward = move down } else if (beta < -tiltThreshold) { moveUfo(0, -1); // tilt backward = move up } if (gamma > tiltThreshold) { moveUfo(1, 0); // tilt right = move right } else if (gamma < -tiltThreshold) { moveUfo(-1, 0); // tilt left = move left } } // Initialize game function initGame() { resizeCanvas(); window.addEventListener('resize', resizeCanvas); // Add device orientation listener if (window.DeviceOrientationEvent) { window.addEventListener('deviceorientation', handleOrientation); } // Set maze size based on difficulty switch(difficultySelect.value) { case 'easy': mazeSize = 15; break; case 'medium': mazeSize = 25; break; case 'hard': mazeSize = 35; break; } // Generate maze generateMaze(); drawMaze(); // Set up keyboard controls document.addEventListener('keydown', handleKeyPress); upBtn.addEventListener('click', () => moveUfo(0, -1)); downBtn.addEventListener('click', () => moveUfo(0, 1)); leftBtn.addEventListener('click', () => moveUfo(-1, 0)); rightBtn.addEventListener('click', () => moveUfo(1, 0)); // Start button startBtn.addEventListener('click', startGame); } // Generate maze using depth-first search function generateMaze() { // Initialize maze grid maze = Array(mazeSize).fill().map(() => Array(mazeSize).fill(1)); // Start position (top-left corner) ufo = { x: 0, y: 0 }; maze[ufo.y][ufo.x] = 0; // Exit position (bottom-right corner) exit = { x: mazeSize - 1, y: mazeSize - 1 }; // Generate paths const stack = [{ x: ufo.x, y: ufo.y }]; const directions = [ { dx: 1, dy: 0 }, { dx: -1, dy: 0 }, { dx: 0, dy: 1 }, { dx: 0, dy: -1 }, { dx: 1, dy: 1 }, { dx: -1, dy: -1 }, { dx: 1, dy: -1 }, { dx: -1, dy: 1 } ]; while (stack.length > 0) { const current = stack[stack.length - 1]; const neighbors = []; // Find unvisited neighbors for (const dir of directions) { // For diagonal directions, make paths longer to prevent too many walls const step = (Math.abs(dir.dx) + Math.abs(dir.dy) === 2) ? 3 : 2; const nx = current.x + dir.dx * step; const ny = current.y + dir.dy * step; if (nx >= 0 && nx < mazeSize && ny >= 0 && ny < mazeSize && maze[ny][nx] === 1) { neighbors.push({ x: nx, y: ny, dir }); } } if (neighbors.length > 0) { const next = neighbors[Math.floor(Math.random() * neighbors.length)]; // Carve out the path for (let i = 1; i <= (Math.abs(next.dir.dx) + Math.abs(next.dir.dy) === 2 ? 3 : 2); i++) { const pathX = current.x + next.dir.dx * i; const pathY = current.y + next.dir.dy * i; if (pathX >= 0 && pathX < mazeSize && pathY >= 0 && pathY < mazeSize) { maze[pathY][pathX] = 0; } } stack.push({ x: next.x, y: next.y }); } else { stack.pop(); } } // Ensure exit is reachable maze[exit.y][exit.x] = 0; } // Draw maze on canvas function drawMaze() { cellSize = canvas.width / mazeSize; ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw walls ctx.fillStyle = '#374151'; ctx.shadowColor = 'rgba(0, 0, 0, 0.3)'; ctx.shadowBlur = 5; ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; for (let y = 0; y < mazeSize; y++) { for (let x = 0; x < mazeSize; x++) { if (maze[y][x] === 1) { ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); } } } // Draw exit ctx.fillStyle = '#10B981'; ctx.shadowColor = 'rgba(16, 185, 129, 0.5)'; ctx.shadowBlur = 10; ctx.fillRect(exit.x * cellSize, exit.y * cellSize, cellSize, cellSize); // Draw UFO drawUfo(); } // Draw UFO function drawUfo() { const centerX = ufo.x * cellSize + cellSize / 2; const centerY = ufo.y * cellSize + cellSize / 2; const radius = cellSize * 0.3; // UFO body ctx.beginPath(); ctx.ellipse(centerX, centerY, radius, radius * 0.6, 0, 0, Math.PI * 2); ctx.fillStyle = '#7C3AED'; ctx.shadowColor = 'rgba(124, 58, 237, 0.5)'; ctx.shadowBlur = 10; ctx.fill(); // UFO dome ctx.beginPath(); ctx.ellipse(centerX, centerY - radius * 0.2, radius * 0.7, radius * 0.4, 0, 0, Math.PI * 2); ctx.fillStyle = 'rgba(167, 139, 250, 0.7)'; ctx.fill(); // UFO lights ctx.beginPath(); for (let i = 0; i < 5; i++) { const lightX = centerX - radius * 0.6 + i * radius * 0.3; ctx.arc(lightX, centerY + radius * 0.3, radius * 0.1, 0, Math.PI * 2); } ctx.fillStyle = '#F59E0B'; ctx.shadowColor = 'rgba(245, 158, 11, 0.5)'; ctx.shadowBlur = 5; ctx.fill(); } // Handle keyboard input function handleKeyPress(e) { if (!gameRunning) return; switch(e.key) { case 'ArrowUp': moveUfo(0, -1); break; case 'ArrowDown': moveUfo(0, 1); break; case 'ArrowLeft': moveUfo(-1, 0); break; case 'ArrowRight': moveUfo(1, 0); break; } } // Move UFO function moveUfo(dx, dy) { if (!gameRunning || (orientationEnabled && dx === 0 && dy === 0)) return; const newX = ufo.x + dx; const newY = ufo.y + dy; // Check if move is valid if (newX >= 0 && newX < mazeSize && newY >= 0 && newY < mazeSize && maze[newY][newX] === 0) { ufo.x = newX; ufo.y = newY; moves++; movesDisplay.textContent = moves; drawMaze(); // Check if reached exit if (ufo.x === exit.x && ufo.y === exit.y) { endGame(true); } } } // Toggle tilt controls document.getElementById('tilt-control').addEventListener('change', function() { orientationEnabled = this.checked; if (orientationEnabled && !gameRunning) { alert('Tilt controls enabled! Tilt your device to move the UFO.'); } }); // Start game function startGame() { if (gameRunning) return; // Reset game state moves = 0; time = 0; movesDisplay.textContent = moves; timeDisplay.textContent = '00:00'; // Generate new maze generateMaze(); drawMaze(); // Start timer gameRunning = true; timer = setInterval(() => { time++; const minutes = Math.floor(time / 60).toString().padStart(2, '0'); const seconds = (time % 60).toString().padStart(2, '0'); timeDisplay.textContent = `${minutes}:${seconds}`; }, 1000); startBtn.textContent = 'Restart Game'; } // End game function endGame(win) { gameRunning = false; clearInterval(timer); if (win) { setTimeout(() => { alert(`Congratulations! You escaped the maze in ${time} seconds with ${moves} moves!`); }, 100); } } // Initialize the game initGame(); });