You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS实现贪吃蛇时按键无法正确修改方向向量的解决方法

问题根因

方向向量无法修改是多个代码错误共同导致的:

  • 键盘事件回调函数额外声明了vectorX、vectorY形参,直接遮蔽了全局的同名方向变量,回调内的赋值只会修改局部形参,不会影响全局控制蛇移动的变量。
  • 按键判断逻辑错误:keydown回调传入的第一个参数是KeyboardEvent事件对象,不是按键字符串,直接和"w""a""s""d"比较永远不会匹配,你看到的[object KeyboardEvent]就是这个对象转字符串的结果,实际按键值存在event.key属性中。
  • 事件绑定位置错误:你把addEventListener写在了逐帧执行的snakeRender函数里,每1秒渲染一次就会多绑定一个重复的键盘回调,按一次键会触发多次逻辑,最终方向值会被覆盖。
  • 初始值与逻辑瑕疵:初始方向向量设为(0,0),打开页面蛇不会自动移动;另外没有做反向移动拦截,蛇移动时可以直接180度掉头撞到自己。
  • 方向映射写反:Canvas坐标系y轴向下为正,你原来写的按w时vectorY=1实际是向下移动,和常规WASD操作直觉相反。
修复方案
  1. 将键盘事件绑定移到snakeRender函数外部,页面加载时只绑定一次即可
  2. 删除键盘回调中多余的vectorX、vectorY形参,直接修改全局方向变量
  3. 读取event.key.toLowerCase()获取实际按下的按键值,再做分支判断
  4. 设置初始方向为向右(vectorX=1, vectorY=0),打开页面蛇自动开始移动
  5. 增加反向移动拦截,禁止蛇在移动时直接180度掉头
  6. 修正WASD的方向映射,符合上w下s左a右d的操作习惯
修复后完整代码

JavaScript 部分(script.js)

const canvas = document.getElementById('map');
const cs = canvas.getContext('2d');

function drawSqr(color, size, position){
    cs.fillStyle = color;
    cs.fillRect(position[0] * size, position[1] * size, size, size);
}

const sqrSize = 20;
cs.fillStyle = "#000000";
cs.fillRect(0, 0, canvas.width, canvas.height);

// 初始方向:向右
let vectorX = 1, vectorY = 0;

let snake = {
    position : [
        [1, 1],
        [2, 1],
        [3, 1],
    ],
    color: "#00FFFF",
    snakeRender: function(){
        const [headX, headY] = this.position.at(-1);
        this.position.push([headX + vectorX, headY + vectorY]);
        const oldTail = this.position.shift();
        // 覆盖旧尾部
        drawSqr("#000000", sqrSize, oldTail);
        // 重绘蛇身
        for(let pos of this.position){
            drawSqr(this.color, sqrSize, pos);
        }
        setTimeout(() => snake.snakeRender(), 1000);
    }
};

// 键盘事件全局只绑定一次
document.addEventListener('keydown', function(event){
    const pressKey = event.key.toLowerCase();
    switch(pressKey){
        case "w":
            // 正在向下移动时禁止直接向上
            if (vectorY !== 1) {
                vectorX = 0;
                vectorY = -1;
            }
            break;
        case "a":
            // 正在向右移动时禁止直接向左
            if (vectorX !== 1) {
                vectorX = -1;
                vectorY = 0;
            }
            break;
        case "s":
            // 正在向上移动时禁止直接向下
            if (vectorY !== -1) {
                vectorX = 0;
                vectorY = 1;
            }
            break;
        case "d":
            // 正在向左移动时禁止直接向右
            if (vectorX !== -1) {
                vectorX = 1;
                vectorY = 0;
            }
            break;
    }
});

snake.snakeRender();

HTML 部分(index.html)

<!DOCTYPE html>
<html>
 <head>
   <title>The snake</title>
   <meta charset="utf-8">
 </head>
 <body>
    <canvas id="map" width="1280" height="720"></canvas>
    <script src="script.js"></script>
 </body> 
</html>

注:setTimeout本身不是导致问题的原因,核心问题是事件绑定和变量作用域的写法错误。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:51:21