You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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);
修复说明
  • 通过dxdy记录当前移动方向,按键时判断是否反向,从根源避免头部与身体重叠的问题。
  • 使用setInterval实现蛇的持续自动移动,按键仅负责改变方向,符合贪吃蛇的常规玩法逻辑。
  • 给canvas设置固定宽高,确保绘制区域明确,避免绘制异常。

内容的提问来源于stack exchange,提问作者amirStreaver

火山引擎 最新活动