Vanilla JS贪吃蛇游戏Bug:按左右箭头蛇长度异常变化
问题分析
你遇到的蛇长度“缩短”其实是视觉错觉,本质是蛇直接掉头向身体方向移动时,新头部与身体部位位置重叠,导致多个蛇身在同一坐标被绘制,看起来像是长度减少。而多次按键后,蛇移动出重叠区域,视觉上就恢复了正常长度。
问题核心原因:
- 没有限制蛇的反向移动,允许蛇直接向身体方向掉头,导致头部与身体重叠。
- 移动逻辑仅在按键时触发,不符合贪吃蛇持续自动移动的常规运行逻辑。
修复方案
1. 记录当前移动方向,阻止反向操作
添加变量记录蛇的当前移动方向,按键时判断是否为反向操作,禁止直接掉头。
2. 实现持续自动移动循环
贪吃蛇应持续自动移动,按键仅用于改变方向,而非每次按键才移动一次,这样能避免单次按键导致的重叠问题。
修复后的完整代码
<canvas id="gameCanvas" width="400" height="400"></canvas>
"use strict"; const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); canvas.width = 400; canvas.height = 400; const gridSize = 10; let dx = gridSize; // 横向移动步长:正数向右,负数向左 let dy = 0; // 纵向移动步长:正数向下,负数向上 let snake = [ { x: 150, y: 150 }, { x: 140, y: 150 }, { x: 130, y: 150 }, { x: 120, y: 150 }, { x: 110, y: 150 }, ]; const drawSnakePart = function (snakePart) { ctx.fillStyle = "lightgreen"; ctx.strokeStyle = "darkgreen"; ctx.fillRect(snakePart.x, snakePart.y, gridSize, gridSize); ctx.strokeRect(snakePart.x, snakePart.y, gridSize, gridSize); }; const drawSnake = function () { snake.forEach(drawSnakePart); }; const advanceSnake = function () { // 创建新头部 const head = { x: snake[0].x + dx, y: snake[0].y + dy }; snake.unshift(head); // 未吃到食物时移除尾部,保持长度不变 snake.pop(); // 清除画布并重新绘制蛇 ctx.clearRect(0, 0, canvas.width, canvas.height); drawSnake(); }; const changeDirection = function (event) { const keyPressed = event.key; const goingUp = dy === -gridSize; const goingDown = dy === gridSize; const goingRight = dx === gridSize; const goingLeft = dx === -gridSize; // 禁止反向移动 switch (keyPressed) { case "ArrowLeft": if (!goingRight) { dx = -gridSize; dy = 0; } break; case "ArrowRight": if (!goingLeft) { dx = gridSize; dy = 0; } break; case "ArrowUp": if (!goingDown) { dy = -gridSize; dx = 0; } break; case "ArrowDown": if (!goingUp) { dy = gridSize; dx = 0; } break; } }; // 监听方向键事件 document.addEventListener("keydown", changeDirection); // 启动自动移动循环,每100ms移动一次 setInterval(advanceSnake, 100);
修复说明
- 通过
dx和dy记录当前移动方向,按键时判断是否反向,从根源避免头部与身体重叠的问题。 - 使用
setInterval实现蛇的持续自动移动,按键仅负责改变方向,符合贪吃蛇的常规玩法逻辑。 - 给canvas设置固定宽高,确保绘制区域明确,避免绘制异常。
内容的提问来源于stack exchange,提问作者amirStreaver




