Creation chat
ClarkZhang
Do you know video game: snake ?
02-25 08:58
暂无回复
No comments yet
登录 后可以评论
Assistant
I'll create a classic Snake game for you using HTML5 Canvas and JavaScript. This implementation will be responsive, work on both mobile and desktop, and include touch controls.
(HTML code has been generated and updated; see above for the current version.)
This Snake game includes:
1. **Classic Snake gameplay** - Control a snake to eat food and grow longer
2. **Responsive design** - Works on both mobile and desktop devices
3. **Touch controls** - Swipe gestures for mobile play
4. **Keyboard controls** - Arrow keys for desktop play
5. **Directional buttons** - On-screen controls for mobile users
6. **Score tracking** - Current score and high score display
7. **Dark/light mode** - Toggle between themes with persistent settings
8. **Game states** - Start screen, gameplay, and game over screen
9. **Progressive difficulty** - Game speeds up as you score more points
10. **Persistent high score** - Saved in localStorage
To play:
- Use arrow keys or on-screen buttons to control the snake
- Eat the red food to grow and increase your score
- Avoid hitting walls or the snake's own body
- The game gets faster as your score increases
The game features a clean, modern design with the "Modern Blue" color palette as requested. The canvas is set to a fixed size that works well in iframes, and all interactive elements are mobile-friendly with proper touch handling.
▼ Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>tailwind.config = { darkMode: 'class' }</script>
<style>
canvas {
image-rendering: pixelated;
}
</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 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-2xl flex flex-col items-center">
<h1 class="text-3xl font-bold mb-2 text-center">Snake Game</h1>
<p class="text-slate-700 dark:text-slate-300 mb-6 text-center">Use arrow keys or swipe to control the snake</p>
<div class="relative w-full mb-4">
<canvas id="gameCanvas" class="w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-slate-200 dark:border-slate-700 touch-none" width="400" height="400"></canvas>
<!-- Game Over Overlay -->
<div id="gameOver" class="absolute inset-0 bg-black/70 rounded-lg flex flex-col items-center justify-center hidden">
<h2 class="text-2xl font-bold text-white mb-4">Game Over!</h2>
<p id="finalScore" class="text-xl text-white mb-6">Score: 0</p>
<button id="restartBtn" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors">Play Again</button>
</div>
<!-- Start Screen -->
<div id="startScreen" class="absolute inset-0 bg-black/70 rounded-lg flex flex-col items-center justify-center">
<h2 class="text-2xl font-bold text-white mb-4">Snake Game</h2>
<p class="text-white mb-2">Use arrow keys or swipe to play</p>
<p class="text-white mb-6">Eat food to grow and earn points!</p>
<button id="startBtn" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors">Start Game</button>
</div>
</div>
<div class="w-full flex justify-between items-center mb-4">
<div class="text-lg font-semibold">
Score: <span id="score">0</span>
</div>
<div class="text-lg font-semibold">
High Score: <span id="highScore">0</span>
</div>
</div>
<div class="grid grid-cols-3 gap-4 w-full max-w-xs mt-4">
<div></div>
<button id="upBtn" class="p-4 bg-slate-200 dark:bg-slate-700 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-slate-700 dark:text-slate-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path></svg>
</button>
<div></div>
<button id="leftBtn" class="p-4 bg-slate-200 dark:bg-slate-700 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-slate-700 dark:text-slate-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
</button>
<div></div>
<button id="rightBtn" class="p-4 bg-slate-200 dark:bg-slate-700 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-slate-700 dark:text-slate-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
</button>
<div></div>
<button id="downBtn" class="p-4 bg-slate-200 dark:bg-slate-700 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-slate-700 dark:text-slate-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div></div>
</div>
</div>
<script>
// Game constants
const GRID_SIZE = 20;
const TILE_COUNT = 20;
const INITIAL_SPEED = 150;
// Game variables
let canvas, ctx;
let snake = [];
let food = {};
let direction = 'right';
let nextDirection = 'right';
let score = 0;
let highScore = localStorage.getItem('snakeHighScore') || 0;
let gameSpeed = INITIAL_SPEED;
let gameRunning = false;
let gameLoop;
// DOM elements
const scoreElement = document.getElementById('score');
const highScoreElement = document.getElementById('highScore');
const finalScoreElement = document.getElementById('finalScore');
const gameOverElement = document.getElementById('gameOver');
const startScreenElement = document.getElementById('startScreen');
const gameCanvas = document.getElementById('gameCanvas');
// Initialize game
function init() {
canvas = gameCanvas;
ctx = canvas.getContext('2d');
// Set high score display
highScoreElement.textContent = highScore;
// Event listeners for buttons
document.getElementById('startBtn').addEventListener('click', startGame);
document.getElementById('restartBtn').addEventListener('click', startGame);
// Direction buttons
document.getElementById('upBtn').addEventListener('click', () => changeDirection('up'));
document.getElementById('downBtn').addEventListener('click', () => changeDirection('down'));
document.getElementById('leftBtn').addEventListener('click', () => changeDirection('left'));
document.getElementById('rightBtn').addEventListener('click', () => changeDirection('right'));
// Keyboard controls
document.addEventListener('keydown', handleKeyDown);
// Touch controls for mobile
let touchStartX = 0;
let touchStartY = 0;
canvas.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
e.preventDefault();
}, { passive: false });
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
}, { passive: false });
canvas.addEventListener('touchend', (e) => {
const touchEndX = e.changedTouches[0].clientX;
const touchEndY = e.changedTouches[0].clientY;
const diffX = touchEndX - touchStartX;
const diffY = touchEndY - touchStartY;
// Determine swipe direction
if (Math.abs(diffX) > Math.abs(diffY)) {
// Horizontal swipe
if (diffX > 0) {
changeDirection('right');
} else {
changeDirection('left');
}
} else {
// Vertical swipe
if (diffY > 0) {
changeDirection('down');
} else {
changeDirection('up');
}
}
e.preventDefault();
}, { passive: false });
}
// Start the game
function startGame() {
// Reset game state
snake = [
{x: 10, y: 10},
{x: 9, y: 10},
{x: 8, y: 10}
];
direction = 'right';
nextDirection = 'right';
score = 0;
gameSpeed = INITIAL_SPEED;
scoreElement.textContent = score;
// Hide screens
gameOverElement.classList.add('hidden');
startScreenElement.classList.add('hidden');
// Generate first food
generateFood();
// Start game loop
if (gameLoop) clearInterval(gameLoop);
gameRunning = true;
gameLoop = setInterval(update, gameSpeed);
}
// Generate food at random position
function generateFood() {
// Create new food position
food = {
x: Math.floor(Math.random() * TILE_COUNT),
y: Math.floor(Math.random() * TILE_COUNT)
};
// Make sure food doesn't appear on snake
for (let segment of snake) {
if (segment.x === food.x && segment.y === food.y) {
return generateFood();
}
}
}
// Update game state
function update() {
// Update direction
direction = nextDirection;
// Calculate new head position
const head = {x: snake[0].x, y: snake[0].y};
switch (direction) {
case 'up': head.y--; break;
case 'down': head.y++; break;
case 'left': head.x--; break;
case 'right': head.x++; break;
}
// Check collision with walls
if (head.x < 0 || head.x >= TILE_COUNT || head.y < 0 || head.y >= TILE_COUNT) {
gameOver();
return;
}
// Check collision with self
for (let i = 0; i < snake.length; i++) {
if (snake[i].x === head.x && snake[i].y === head.y) {
gameOver();
return;
}
}
// Add new head
snake.unshift(head);
// Check if food is eaten
if (head.x === food.x && head.y === food.y) {
// Increase score
score += 10;
scoreElement.textContent = score;
// Generate new food
generateFood();
// Increase speed slightly
if (gameSpeed > 50) {
gameSpeed -= 2;
clearInterval(gameLoop);
gameLoop = setInterval(update, gameSpeed);
}
} else {
// Remove tail if no food eaten
snake.pop();
}
// Draw everything
draw();
}
// Draw game state
function draw() {
// Clear canvas
ctx.fillStyle = document.documentElement.classList.contains('dark') ? '#1e293b' : '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw grid
ctx.strokeStyle = document.documentElement.classList.contains('dark') ? '#334155' : '#e2e8f0';
ctx.lineWidth = 0.5;
for (let i = 0; i < TILE_COUNT; i++) {
for (let j = 0; j < TILE_COUNT; j++) {
ctx.strokeRect(i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE);
}
}
// Draw snake
snake.forEach((segment, index) => {
if (index === 0) {
// Draw head
ctx.fillStyle = document.documentElement.classList.contains('dark') ? '#3b82f6' : '#2563eb';
} else {
// Draw body
ctx.fillStyle = document.documentElement.classList.contains('dark') ? '#60a5fa' : '#3b82f6';
}
ctx.fillRect(segment.x * GRID_SIZE, segment.y * GRID_SIZE, GRID_SIZE, GRID_SIZE);
// Add border to segments
ctx.strokeStyle = document.documentElement.classList.contains('dark') ? '#1e40af' : '#1d4ed8';
ctx.lineWidth = 1;
ctx.strokeRect(segment.x * GRID_SIZE, segment.y * GRID_SIZE, GRID_SIZE, GRID_SIZE);
});
// Draw food
ctx.fillStyle = document.documentElement.classList.contains('dark') ? '#ef4444' : '#dc2626';
ctx.beginPath();
ctx.arc(
food.x * GRID_SIZE + GRID_SIZE/2,
food.y * GRID_SIZE + GRID_SIZE/2,
GRID_SIZE/2,
0,
Math.PI * 2
);
ctx.fill();
}
// Handle keyboard input
function handleKeyDown(e) {
if (!gameRunning) return;
switch (e.key) {
case 'ArrowUp':
changeDirection('up');
break;
case 'ArrowDown':
changeDirection('down');
break;
case 'ArrowLeft':
changeDirection('left');
break;
case 'ArrowRight':
changeDirection('right');
break;
}
}
// Change direction with validation
function changeDirection(newDirection) {
// Prevent 180-degree turns
if (
(direction === 'up' && newDirection === 'down') ||
(direction === 'down' && newDirection === 'up') ||
(direction === 'left' && newDirection === 'right') ||
(direction === 'right' && newDirection === 'left')
) {
return;
}
nextDirection = newDirection;
}
// Game over
function gameOver() {
gameRunning = false;
clearInterval(gameLoop);
// Update high score
if (score > highScore) {
highScore = score;
localStorage.setItem('snakeHighScore', highScore);
highScoreElement.textContent = highScore;
}
// Show game over screen
finalScoreElement.textContent = `Score: ${score}`;
gameOverElement.classList.remove('hidden');
}
// Initialize when page loads
window.onload = init;
</script>
</body>
</html>
02-25 09:01
暂无回复
No comments yet
登录 后可以评论
Comments
暂无回复
No comments yet
登录 后可以评论