Back to Hello Agents

Patch applied

Co-creation-projects/YYHDBL-HelloCodeAgentCli/.helloagents/notes/note_20251219_171820_21.md

1.0.29.8 KB
Original Source

Patch applied

User input: 用户想创建一个贪吃蛇游戏的 MVP 版本,用 HTML、CSS、JS

Patch:

text
*** Begin Patch
*** Add File: testDemo/snake.js
// Snake Game MVP - JavaScript Implementation
document.addEventListener('DOMContentLoaded', function() {
    // Game variables
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const scoreElement = document.getElementById('score');
    const highScoreElement = document.getElementById('highScore');
    const speedElement = document.getElementById('speed');
    const startBtn = document.getElementById('startBtn');
    const pauseBtn = document.getElementById('pauseBtn');
    const resetBtn = document.getElementById('resetBtn');
    
    // Game constants
    const GRID_SIZE = 20;
    const GRID_WIDTH = canvas.width / GRID_SIZE;
    const GRID_HEIGHT = canvas.height / GRID_SIZE;
    
    // Game state
    let snake = [];
    let food = {};
    let direction = 'right';
    let nextDirection = 'right';
    let gameSpeed = 150; // ms
    let score = 0;
    let highScore = localStorage.getItem('snakeHighScore') || 0;
    let gameRunning = false;
    let gameLoop;
    let foodsEaten = 0;
    
    // Initialize game
    function init() {
        // Initialize snake
        snake = [
            {x: 5, y: 10},
            {x: 4, y: 10},
            {x: 3, y: 10}
        ];
        
        // Generate first food
        generateFood();
        
        // Reset score and speed
        score = 0;
        foodsEaten = 0;
        updateScore();
        updateSpeedDisplay();
        
        // Draw initial state
        draw();
    }
    
    // Generate food at random position
    function generateFood() {
        let newFood;
        let foodOnSnake;
        
        do {
            foodOnSnake = false;
            newFood = {
                x: Math.floor(Math.random() * GRID_WIDTH),
                y: Math.floor(Math.random() * GRID_HEIGHT)
            };
            
            // Check if food is on snake
            for (let segment of snake) {
                if (segment.x === newFood.x && segment.y === newFood.y) {
                    foodOnSnake = true;
                    break;
                }
            }
        } while (foodOnSnake);
        
        food = newFood;
    }
    
    // Draw game elements
    function draw() {
        // Clear canvas
        ctx.fillStyle = '#000';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        
        // Draw snake
        ctx.fillStyle = '#00ff88';
        for (let i = 0; i < snake.length; i++) {
            const segment = snake[i];
            // Head is slightly brighter
            if (i === 0) {
                ctx.fillStyle = '#00ff88';
            } else {
                ctx.fillStyle = '#00cc6a';
            }
            ctx.fillRect(
                segment.x * GRID_SIZE, 
                segment.y * GRID_SIZE, 
                GRID_SIZE - 1, 
                GRID_SIZE - 1
            );
        }
        
        // Draw food
        ctx.fillStyle = '#ff5555';
        ctx.beginPath();
        ctx.arc(
            food.x * GRID_SIZE + GRID_SIZE / 2,
            food.y * GRID_SIZE + GRID_SIZE / 2,
            GRID_SIZE / 2 - 1,
            0,
            Math.PI * 2
        );
        ctx.fill();
        
        // Draw grid (optional, for debugging)
        // drawGrid();
    }
    
    // Draw grid lines (for debugging)
    function drawGrid() {
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 0.5;
        
        // Vertical lines
        for (let x = 0; x <= canvas.width; x += GRID_SIZE) {
            ctx.beginPath();
            ctx.moveTo(x, 0);
            ctx.lineTo(x, canvas.height);
            ctx.stroke();
        }
        
        // Horizontal lines
        for (let y = 0; y <= canvas.height; y += GRID_SIZE) {
            ctx.beginPath();
            ctx.moveTo(0, y);
            ctx.lineTo(canvas.width, y);
            ctx.stroke();
        }
    }
    
    // Update game state
    function update() {
        // Update direction
        direction = nextDirection;
        
        // Calculate new head position
        const head = {...snake[0]};
        
        switch (direction) {
            case 'up': head.y--; break;
            case 'down': head.y++; break;
            case 'left': head.x--; break;
            case 'right': head.x++; break;
        }
        
        // Check wall collision
        if (
            head.x < 0 || 
            head.x >= GRID_WIDTH || 
            head.y < 0 || 
            head.y >= GRID_HEIGHT
        ) {
            gameOver();
            return;
        }
        
        // Check self collision
        for (let segment of snake) {
            if (head.x === segment.x && head.y === segment.y) {
                gameOver();
                return;
            }
        }
        
        // Add new head
        snake.unshift(head);
        
        // Check food collision
        if (head.x === food.x && head.y === food.y) {
            // Increase score
            score += 10;
            foodsEaten++;
            
            // Update high score if needed
            if (score > highScore) {
                highScore = score;
                localStorage.setItem('snakeHighScore', highScore);
            }
            
            // Increase speed every 5 foods
            if (foodsEaten % 5 === 0 && gameSpeed > 50) {
                gameSpeed -= 20;
                updateSpeedDisplay();
                clearInterval(gameLoop);
                if (gameRunning) {
                    gameLoop = setInterval(gameStep, gameSpeed);
                }
            }
            
            // Generate new food
            generateFood();
            updateScore();
        } else {
            // Remove tail if no food eaten
            snake.pop();
        }
        
        // Draw updated state
        draw();
    }
    
    // Game step (called by interval)
    function gameStep() {
        if (gameRunning) {
            update();
        }
    }
    
    // Update score display
    function updateScore() {
        scoreElement.textContent = score;
        highScoreElement.textContent = highScore;
    }
    
    // Update speed display
    function updateSpeedDisplay() {
        if (gameSpeed >= 130) {
            speedElement.textContent = 'Slow';
        } else if (gameSpeed >= 90) {
            speedElement.textContent = 'Normal';
        } else if (gameSpeed >= 70) {
            speedElement.textContent = 'Fast';
        } else if (gameSpeed >= 50) {
            speedElement.textContent = 'Very Fast';
        } else {
            speedElement.textContent = 'Extreme';
        }
    }
    
    // Game over
    function gameOver() {
        gameRunning = false;
        clearInterval(gameLoop);
        
        // Show game over overlay
        const gameOverDiv = document.createElement('div');
        gameOverDiv.className = 'game-over';
        gameOverDiv.innerHTML = `
            <h2>Game Over!</h2>
            <p>Final Score: ${score}</p>
            <p>High Score: ${highScore}</p>
            <button class="btn btn-primary" onclick="this.parentElement.remove();">OK</button>
        `;
        
        // Add to game board
        const gameBoard = document.querySelector('.game-board');
        gameBoard.appendChild(gameOverDiv);
        
        // Update button states
        startBtn.disabled = false;
        pauseBtn.disabled = true;
    }
    
    // Start game
    function startGame() {
        if (!gameRunning) {
            gameRunning = true;
            gameLoop = setInterval(gameStep, gameSpeed);
            
            // Update button states
            startBtn.disabled = true;
            pauseBtn.disabled = false;
        }
    }
    
    // Pause game
    function pauseGame() {
        if (gameRunning) {
            gameRunning = false;
            clearInterval(gameLoop);
            
            // Update button states
            startBtn.disabled = false;
            pauseBtn.disabled = true;
        }
    }
    
    // Reset game
    function resetGame() {
        // Clear any game over overlay
        const gameOverDiv = document.querySelector('.game-over');
        if (gameOverDiv) {
            gameOverDiv.remove();
        }
        
        // Stop game if running
        if (gameRunning) {
            clearInterval(gameLoop);
            gameRunning = false;
        }
        
        // Reinitialize
        init();
        
        // Update button states
        startBtn.disabled = false;
        pauseBtn.disabled = true;
    }
    
    // Keyboard controls
    document.addEventListener('keydown', function(e) {
        switch (e.key) {
            case 'ArrowUp':
            case 'w':
            case 'W':
                if (direction !== 'down') nextDirection = 'up';
                break;
            case 'ArrowDown':
            case 's':
            case 'S':
                if (direction !== 'up') nextDirection = 'down';
                break;
            case 'ArrowLeft':
            case 'a':
            case 'A':
                if (direction !== 'right') nextDirection = 'left';
                break;
            case 'ArrowRight':
            case 'd':
            case 'D':
                if (direction !== 'left') nextDirection = 'right';
                break;
            case ' ':
                if (gameRunning) {
                    pauseGame();
                } else {
                    startGame();
                }
                break;
        }
    });
    
    // Button event listeners
    startBtn.addEventListener('click', startGame);
    pauseBtn.addEventListener('click', pauseGame);
    resetBtn.addEventListener('click', resetGame);
    
    // Initialize game on load
    init();
    
    // Update button states
    pauseBtn.disabled = true;
});
*** End Patch

Files:

  • testDemo/snake.js