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操作直觉相反。
修复方案
- 将键盘事件绑定移到
snakeRender函数外部,页面加载时只绑定一次即可 - 删除键盘回调中多余的
vectorX、vectorY形参,直接修改全局方向变量 - 读取
event.key.toLowerCase()获取实际按下的按键值,再做分支判断 - 设置初始方向为向右(vectorX=1, vectorY=0),打开页面蛇自动开始移动
- 增加反向移动拦截,禁止蛇在移动时直接180度掉头
- 修正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
相关产品推荐
相关产品推荐

