ufo-maze-runner / script.js
CommanderLazarus's picture
Make the board more complex. Use 25 squares by 25 squares as the measurement.
b00966f verified
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();
});