--- id: note_20251219_171820_21 title: Patch applied type: action tags: ["hello_agents_forStudy", "patch_applied"] created_at: 2025-12-19T17:18:20.676780 updated_at: 2025-12-19T17:18:20.676784 --- # 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 = `
Final Score: ${score}
High Score: ${highScore}
`; // 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