Creation chat
ClarkZhang
make me a maze game
02-28 00:49
暂无回复
No comments yet
登录 后可以评论
Assistant
# Maze Game Implementation
I'll create a responsive maze game with a clean design that works well on both mobile and desktop. The game will feature keyboard controls for desktop and touch controls for mobile devices.
(HTML code has been generated and updated; see above for the current version.)
## Features of the Maze Game:
1. **Responsive Design**: Works on both mobile and desktop devices
2. **Theme Support**: Light and dark mode with toggle button
3. **Game Mechanics**:
- Navigate through a randomly generated maze
- Move counter to track your progress
- Win screen when you reach the goal
4. **Controls**:
- Keyboard arrow keys for desktop
- On-screen buttons for mobile
- Swipe gestures for mobile
5. **Visual Design**:
- Clean, modern interface with Tailwind CSS
- Color-coded elements (player, goal, walls)
- Smooth animations and transitions
6. **Game Features**:
- Generate new mazes with the click of a button
- Restart functionality
- Move counter
The game is contained within a fixed-size container to ensure it's visible in iframes, and all interactive elements are designed to work well on touch devices with appropriate spacing and touch targets.
To play:
1. Use arrow keys on desktop or on-screen buttons/swipe on mobile to navigate
2. Try to reach the green goal circle with the fewest moves
3. Click "Generate New Maze" to create a new challenge
4. Toggle between light and dark mode using the button in the top-right corner
The console in the bottom-right of the preview can be used to check for any logs or errors during gameplay.
▼ Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Maze Runner Game</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>tailwind.config = { darkMode: 'class' }</script>
<style>
.maze-cell {
transition: background-color 0.2s;
}
.player-cell {
background-color: #3b82f6;
border-radius: 50%;
z-index: 10;
}
.goal-cell {
background-color: #10b981;
border-radius: 50%;
}
.wall-cell {
background-color: #94a3b8;
}
.path-cell {
background-color: #e2e8f0;
}
.visited-cell {
background-color: #dbeafe;
}
.dark .path-cell {
background-color: #1e293b;
}
.dark .visited-cell {
background-color: #1e3a8a;
}
.dark .wall-cell {
background-color: #64748b;
}
.touch-controls {
touch-action: manipulation;
}
</style>
</head>
<body class="min-h-screen bg-slate-50 dark:bg-slate-900 text-slate-900 dark:text-slate-100 flex flex-col items-center justify-center p-4">
<!-- Theme toggle button -->
<button id="theme-toggle-btn" class="fixed top-4 right-4 z-10 p-2 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 transition-colors flex items-center justify-center" aria-label="Toggle theme" onclick="toggleTheme()">
<svg id="icon-moon" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998z"/></svg>
<svg id="icon-sun" class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true" style="display:none"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"></path></svg>
</button>
<script>
function toggleTheme(){
var el=document.documentElement;
var isDark=!el.classList.contains('dark');
el.classList.toggle('dark',isDark);
localStorage.setItem('theme',isDark?'dark':'light');
applyTheme(isDark);
}
function applyTheme(isDark){
document.getElementById('icon-moon').style.display=isDark?'none':'block';
document.getElementById('icon-sun').style.display=isDark?'block':'none';
}
document.addEventListener('DOMContentLoaded',function(){
var saved=localStorage.getItem('theme');
var isDark=saved==='dark'||(!saved&&window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('dark',isDark);
applyTheme(isDark);
});
</script>
<div class="w-full max-w-3xl flex flex-col items-center">
<header class="text-center mb-6">
<h1 class="text-3xl md:text-4xl font-bold mb-2">Maze Runner</h1>
<p class="text-slate-600 dark:text-slate-300 mb-4">Navigate through the maze to reach the goal!</p>
</header>
<div class="w-full bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4 mb-6">
<div class="flex justify-between items-center mb-4">
<div class="flex items-center space-x-4">
<div class="flex items-center">
<div class="w-4 h-4 bg-blue-500 rounded-full mr-2"></div>
<span class="text-sm">Player</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-emerald-500 rounded-full mr-2"></div>
<span class="text-sm">Goal</span>
</div>
</div>
<div class="text-lg font-semibold">
Moves: <span id="move-count">0</span>
</div>
</div>
<div class="relative">
<div id="maze-container" class="mx-auto w-full max-w-md aspect-square bg-slate-100 dark:bg-slate-700 rounded-lg overflow-hidden border border-slate-200 dark:border-slate-600">
<!-- Maze will be generated here -->
</div>
<div id="win-message" class="absolute inset-0 flex items-center justify-center bg-black/70 rounded-lg hidden">
<div class="text-center p-6 bg-white dark:bg-slate-800 rounded-xl">
<h2 class="text-2xl font-bold mb-2">Congratulations!</h2>
<p class="mb-4">You solved the maze in <span id="final-moves" class="font-bold">0</span> moves!</p>
<button id="restart-btn" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors">Play Again</button>
</div>
</div>
</div>
</div>
<!-- Mobile Controls -->
<div class="md:hidden w-full max-w-xs mb-6">
<div class="grid grid-cols-3 gap-3">
<div></div>
<button id="up-btn" class="touch-controls bg-slate-200 dark:bg-slate-700 hover:bg-slate-300 dark:hover:bg-slate-600 h-16 rounded-lg flex items-center justify-center text-2xl font-bold">↑</button>
<div></div>
<button id="left-btn" class="touch-controls bg-slate-200 dark:bg-slate-700 hover:bg-slate-300 dark:hover:bg-slate-600 h-16 rounded-lg flex items-center justify-center text-2xl font-bold">←</button>
<button id="down-btn" class="touch-controls bg-slate-200 dark:bg-slate-700 hover:bg-slate-300 dark:hover:bg-slate-600 h-16 rounded-lg flex items-center justify-center text-2xl font-bold">↓</button>
<button id="right-btn" class="touch-controls bg-slate-200 dark:bg-slate-700 hover:bg-slate-300 dark:hover:bg-slate-600 h-16 rounded-lg flex items-center justify-center text-2xl font-bold">→</button>
</div>
</div>
<div class="text-center">
<p class="text-slate-600 dark:text-slate-300 mb-2">Use arrow keys or swipe to move</p>
<button id="new-maze-btn" class="px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg transition-colors">Generate New Maze</button>
</div>
</div>
<script>
// Maze dimensions
const ROWS = 15;
const COLS = 15;
// Game state
let maze = [];
let playerPos = { row: 0, col: 0 };
let goalPos = { row: ROWS - 1, col: COLS - 1 };
let moveCount = 0;
let gameActive = true;
// DOM elements
const mazeContainer = document.getElementById('maze-container');
const moveCountElement = document.getElementById('move-count');
const winMessage = document.getElementById('win-message');
const finalMovesElement = document.getElementById('final-moves');
const restartBtn = document.getElementById('restart-btn');
const newMazeBtn = document.getElementById('new-maze-btn');
// Mobile controls
const upBtn = document.getElementById('up-btn');
const downBtn = document.getElementById('down-btn');
const leftBtn = document.getElementById('left-btn');
const rightBtn = document.getElementById('right-btn');
// Initialize the game
function initGame() {
generateMaze();
renderMaze();
moveCount = 0;
moveCountElement.textContent = moveCount;
gameActive = true;
winMessage.classList.add('hidden');
}
// Generate a simple maze (random walls)
function generateMaze() {
maze = [];
for (let row = 0; row < ROWS; row++) {
maze[row] = [];
for (let col = 0; col < COLS; col++) {
// Create borders
if (row === 0 || row === ROWS - 1 || col === 0 || col === COLS - 1) {
maze[row][col] = 1; // Wall
} else {
// Random walls (30% chance)
maze[row][col] = Math.random() < 0.3 ? 1 : 0;
}
}
}
// Ensure start and end positions are clear
maze[0][0] = 0; // Start
maze[ROWS - 1][COLS - 1] = 0; // End
// Set player and goal positions
playerPos = { row: 0, col: 0 };
goalPos = { row: ROWS - 1, col: COLS - 1 };
}
// Render the maze
function renderMaze() {
mazeContainer.innerHTML = '';
// Create grid container
const grid = document.createElement('div');
grid.className = 'grid w-full h-full';
grid.style.gridTemplateColumns = `repeat(${COLS}, 1fr)`;
grid.style.gridTemplateRows = `repeat(${ROWS}, 1fr)`;
// Render each cell
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
const cell = document.createElement('div');
cell.className = 'maze-cell';
cell.dataset.row = row;
cell.dataset.col = col;
// Apply cell styles based on type
if (row === playerPos.row && col === playerPos.col) {
cell.classList.add('player-cell');
} else if (row === goalPos.row && col === goalPos.col) {
cell.classList.add('goal-cell');
} else if (maze[row][col] === 1) {
cell.classList.add('wall-cell');
} else {
cell.classList.add('path-cell');
}
grid.appendChild(cell);
}
}
mazeContainer.appendChild(grid);
}
// Move player
function movePlayer(direction) {
if (!gameActive) return;
let newRow = playerPos.row;
let newCol = playerPos.col;
switch (direction) {
case 'up':
newRow--;
break;
case 'down':
newRow++;
break;
case 'left':
newCol--;
break;
case 'right':
newCol++;
break;
}
// Check if move is valid
if (newRow >= 0 && newRow < ROWS && newCol >= 0 && newCol < COLS && maze[newRow][newCol] !== 1) {
playerPos.row = newRow;
playerPos.col = newCol;
moveCount++;
moveCountElement.textContent = moveCount;
renderMaze();
// Check if player reached the goal
if (playerPos.row === goalPos.row && playerPos.col === goalPos.col) {
winGame();
}
}
}
// Win game
function winGame() {
gameActive = false;
finalMovesElement.textContent = moveCount;
winMessage.classList.remove('hidden');
}
// Event listeners for keyboard controls
document.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowUp':
movePlayer('up');
e.preventDefault();
break;
case 'ArrowDown':
movePlayer('down');
e.preventDefault();
break;
case 'ArrowLeft':
movePlayer('left');
e.preventDefault();
break;
case 'ArrowRight':
movePlayer('right');
e.preventDefault();
break;
}
});
// Event listeners for mobile controls
upBtn.addEventListener('click', () => movePlayer('up'));
downBtn.addEventListener('click', () => movePlayer('down'));
leftBtn.addEventListener('click', () => movePlayer('left'));
rightBtn.addEventListener('click', () => movePlayer('right'));
// Restart button
restartBtn.addEventListener('click', initGame);
// New maze button
newMazeBtn.addEventListener('click', initGame);
// Initialize the game on load
window.addEventListener('DOMContentLoaded', initGame);
// Add swipe detection for mobile
let touchStartX = 0;
let touchStartY = 0;
mazeContainer.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
touchStartY = e.changedTouches[0].screenY;
}, { passive: false });
mazeContainer.addEventListener('touchend', (e) => {
if (!gameActive) return;
const touchEndX = e.changedTouches[0].screenX;
const touchEndY = e.changedTouches[0].screenY;
const diffX = touchEndX - touchStartX;
const diffY = touchEndY - touchStartY;
// Determine swipe direction
if (Math.abs(diffX) > Math.abs(diffY)) {
// Horizontal swipe
if (diffX > 0) {
movePlayer('right');
} else {
movePlayer('left');
}
} else {
// Vertical swipe
if (diffY > 0) {
movePlayer('down');
} else {
movePlayer('up');
}
}
e.preventDefault();
}, { passive: false });
</script>
</body>
</html>
02-28 00:51
暂无回复
No comments yet
登录 后可以评论
Comments
暂无回复
No comments yet
登录 后可以评论