knip智能工具箱
首页
工具中心
作品展示
登录
注册
贪吃蛇
工具
admin · 2026-08-30 · 使用 7
点赞
0
收藏
0
分享
反馈
经典贪吃蛇游戏,支持键盘和触屏操作,手机电脑都能玩。
贪吃蛇
放大后操作
预览
代码
放大后操作(预览仅供参考)
纯前端工具,无后端代码
换行
HTML
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>贪吃蛇</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #1a1a2e; font-family: 'Segoe UI', sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; touch-action: none; user-select: none; -webkit-user-select: none; } .game-container { background: #16213e; border-radius: 16px; padding: 15px; box-shadow: 0 8px 30px rgba(0,0,0,0.6); max-width: 95vw; max-height: 95vh; display: flex; flex-direction: column; align-items: center; gap: 12px; } .header { display: flex; justify-content: space-between; width: 100%; color: #e0e0e0; font-size: 1.2rem; font-weight: bold; } .score { color: #f7c948; } .best { color: #ff6b6b; } canvas { background: #0f0f1a; border-radius: 8px; display: block; touch-action: none; box-shadow: inset 0 0 10px rgba(0,0,0,0.5); } .controls { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: center; } .btn { background: #0f3460; color: white; border: none; border-radius: 8px; padding: 10px 20px; font-size: 1rem; cursor: pointer; transition: background 0.2s; min-width: 70px; } .btn:hover { background: #1a4a7a; } .btn:active { transform: scale(0.95); } .dpad { display: grid; grid-template-columns: repeat(3, 50px); grid-template-rows: repeat(3, 50px); gap: 5px; justify-content: center; margin-top: 5px; } .dpad-btn { background: #1a1a3a; border: 2px solid #444; border-radius: 10px; color: white; font-size: 1.5rem; display: flex; justify-content: center; align-items: center; cursor: pointer; transition: background 0.2s; } .dpad-btn:active { background: #2a2a5a; } .dpad-btn.up { grid-column: 2; grid-row: 1; } .dpad-btn.left { grid-column: 1; grid-row: 2; } .dpad-btn.down { grid-column: 2; grid-row: 3; } .dpad-btn.right { grid-column: 3; grid-row: 2; } .status { color: #aaa; font-size: 0.9rem; } </style> </head> <body> <div class="game-container"> <div class="header"> <span>🐍 贪吃蛇</span> <span>分数: <span id="score">0</span></span> <span>最高: <span id="best">0</span></span> </div> <canvas id="gameCanvas"></canvas> <div class="controls"> <button class="btn" id="restartBtn">重新开始</button> <button class="btn" id="pauseBtn">暂停</button> </div> <div class="dpad"> <div class="dpad-btn up" data-dir="up">▲</div> <div class="dpad-btn left" data-dir="left">◀</div> <div class="dpad-btn down" data-dir="down">▼</div> <div class="dpad-btn right" data-dir="right">▶</div> </div> <div class="status" id="status">按方向键或点击按钮开始</div> </div> <script> (function() { const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const bestEl = document.getElementById('best'); const statusEl = document.getElementById('status'); const restartBtn = document.getElementById('restartBtn'); const pauseBtn = document.getElementById('pauseBtn'); // 游戏参数 const GRID_SIZE = 20; // 格子大小 let cols, rows; let snake, direction, nextDirection, food, score, bestScore, gameOver, paused, gameLoop; let speed = 150; // 毫秒 // 初始化画布大小 function resizeCanvas() { const maxWidth = Math.min(window.innerWidth - 40, 400); const maxHeight = Math.min(window.innerHeight - 200, 400); const size = Math.min(maxWidth, maxHeight); canvas.width = size; canvas.height = size; cols = Math.floor(size / GRID_SIZE); rows = Math.floor(size / GRID_SIZE); // 确保格子数至少15 if (cols < 15) cols = 15; if (rows < 15) rows = 15; canvas.width = cols * GRID_SIZE; canvas.height = rows * GRID_SIZE; // 重新初始化游戏(如果游戏已开始) if (snake) { resetGame(); } } // 初始化或重置游戏 function resetGame() { snake = [ {x: Math.floor(cols/2), y: Math.floor(rows/2)}, {x: Math.floor(cols/2)-1, y: Math.floor(rows/2)}, {x: Math.floor(cols/2)-2, y: Math.floor(rows/2)}, ]; direction = 'right'; nextDirection = 'right'; score = 0; gameOver = false; paused = false; pauseBtn.textContent = '暂停'; statusEl.textContent = '游戏进行中'; scoreEl.textContent = '0'; generateFood(); clearInterval(gameLoop); gameLoop = setInterval(gameTick, speed); } // 生成食物 function generateFood() { while (true) { food = {x: Math.floor(Math.random()*cols), y: Math.floor(Math.random()*rows)}; if (!snake.some(s => s.x === food.x && s.y === food.y)) break; } } // 游戏主循环 function gameTick() { if (gameOver || paused) return; // 更新方向 direction = nextDirection; // 计算新蛇头 let 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; } // 检查碰撞 if (head.x < 0 || head.x >= cols || head.y < 0 || head.y >= rows || snake.some(s => s.x === head.x && s.y === head.y)) { gameOver = true; clearInterval(gameLoop); statusEl.textContent = '游戏结束!点击重新开始'; if (score > bestScore) { bestScore = score; localStorage.setItem('snakeBest', bestScore); bestEl.textContent = bestScore; } draw(); return; } // 移动蛇 snake.unshift(head); if (head.x === food.x && head.y === food.y) { score++; scoreEl.textContent = score; generateFood(); } else { snake.pop(); } draw(); } // 绘制 function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制网格线(浅色) ctx.strokeStyle = '#2a2a4a'; ctx.lineWidth = 1; for (let i = 0; i <= cols; i++) { ctx.beginPath(); ctx.moveTo(i*GRID_SIZE, 0); ctx.lineTo(i*GRID_SIZE, canvas.height); ctx.stroke(); } for (let i = 0; i <= rows; i++) { ctx.beginPath(); ctx.moveTo(0, i*GRID_SIZE); ctx.lineTo(canvas.width, i*GRID_SIZE); ctx.stroke(); } // 绘制食物 ctx.fillStyle = '#ff4757'; ctx.beginPath(); ctx.arc(food.x*GRID_SIZE + GRID_SIZE/2, food.y*GRID_SIZE + GRID_SIZE/2, GRID_SIZE/2 - 2, 0, Math.PI*2); ctx.fill(); // 绘制蛇 snake.forEach((seg, idx) => { const gradient = ctx.createRadialGradient( seg.x*GRID_SIZE + GRID_SIZE/2, seg.y*GRID_SIZE + GRID_SIZE/2, 2, seg.x*GRID_SIZE + GRID_SIZE/2, seg.y*GRID_SIZE + GRID_SIZE/2, GRID_SIZE/2 ); if (idx === 0) { gradient.addColorStop(0, '#7bed9f'); gradient.addColorStop(1, '#2ed573'); } else { gradient.addColorStop(0, '#3ae374'); gradient.addColorStop(1, '#1e9e4a'); } ctx.fillStyle = gradient; ctx.fillRect(seg.x*GRID_SIZE + 1, seg.y*GRID_SIZE + 1, GRID_SIZE - 2, GRID_SIZE - 2); // 蛇头眼睛 if (idx === 0) { ctx.fillStyle = 'white'; ctx.beginPath(); ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 - 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 3, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 + 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 3, 0, Math.PI*2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 - 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 1.5, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 + 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 1.5, 0, Math.PI*2); ctx.fill(); } }); // 游戏结束后显示遮罩 if (gameOver) { ctx.fillStyle = 'rgba(0,0,0,0.6)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = 'white'; ctx.font = 'bold 24px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('游戏结束', canvas.width/2, canvas.height/2 - 10); ctx.font = '16px sans-serif'; ctx.fillText('点击重新开始', canvas.width/2, canvas.height/2 + 25); } } // 设置方向 function setDirection(dir) { if (gameOver) return; // 防止反向 if ((direction === 'up' && dir === 'down') || (direction === 'down' && dir === 'up') || (direction === 'left' && dir === 'right') || (direction === 'right' && dir === 'left')) { return; } nextDirection = dir; } // 键盘事件 document.addEventListener('keydown', (e) => { switch(e.key) { case 'ArrowUp': e.preventDefault(); setDirection('up'); break; case 'ArrowDown': e.preventDefault(); setDirection('down'); break; case 'ArrowLeft': e.preventDefault(); setDirection('left'); break; case 'ArrowRight': e.preventDefault(); setDirection('right'); break; case ' ': e.preventDefault(); togglePause(); break; } }); // 按钮事件 restartBtn.addEventListener('click', () => { resetGame(); draw(); }); pauseBtn.addEventListener('click', togglePause); function togglePause() { if (gameOver) return; paused = !paused; pauseBtn.textContent = paused ? '继续' : '暂停'; statusEl.textContent = paused ? '已暂停' : '游戏进行中'; } // 方向按钮 document.querySelectorAll('.dpad-btn').forEach(btn => { btn.addEventListener('click', () => { setDirection(btn.dataset.dir); }); }); // 触摸滑动(在canvas上) let touchStartX, touchStartY; canvas.addEventListener('touchstart', (e) => { e.preventDefault(); const touch = e.touches[0]; touchStartX = touch.clientX; touchStartY = touch.clientY; }, {passive: false}); canvas.addEventListener('touchmove', (e) => { e.preventDefault(); }, {passive: false}); canvas.addEventListener('touchend', (e) => { e.preventDefault(); if (touchStartX === undefined) return; const touch = e.changedTouches[0]; const dx = touch.clientX - touchStartX; const dy = touch.clientY - touchStartY; if (Math.abs(dx) < 20 && Math.abs(dy) < 20) return; if (Math.abs(dx) > Math.abs(dy)) { setDirection(dx > 0 ? 'right' : 'left'); } else { setDirection(dy > 0 ? 'down' : 'up'); } touchStartX = undefined; touchStartY = undefined; }, {passive: false}); // 窗口大小改变时重置 window.addEventListener('resize', () => { resizeCanvas(); draw(); }); // 初始化 bestScore = parseInt(localStorage.getItem('snakeBest') || '0'); bestEl.textContent = bestScore; resizeCanvas(); resetGame(); draw(); })(); </script> </body> </html>
评论(0)
暂无评论,来说两句吧
分享「贪吃蛇」
微信扫一扫,分享给朋友
复制链接
QQ 分享
微博分享
微信内也可以点右上角
菜单分享
反馈「贪吃蛇」问题
工具哪里不好用、报错或结果不对?反馈会直接通知作品作者处理。
0 / 500
无需登录,可直接提交
暂无评论,来说两句吧