forks

Creation chat

ClarkZhang
Do you know video game: snake ?
02-25 08:58

登录 后可以评论

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

登录 后可以评论

Comments

登录 后可以评论