我正在创建一个JavaScript蛇游戏,当某些键按顺序过快按下时遇到了问题。例如,(在向右移动时)按下向上箭头,然后过快地向左箭头键会使我的蛇完全转身并撞向自身,而忽略向上箭头键的按下。是否有任何代码可以确保始终显示任何按键?预先感谢。
let d = "RIGHT";
document.addEventListener("keydown", direction);
function direction(event) {
let key = event.keyCode;
if (key == 37 && d != "RIGHT" && d != "LEFT") {
d = "LEFT";
} else if (key == 38 && d != "DOWN" && d != "UP") {
d = "UP";
} else if (key == 39 && d != "LEFT" && d != "RIGHT") {
d = "RIGHT";
} else if (key == 40 && d != "UP" && d != "DOWN") {
d = "DOWN";
}
}
在单独的功能中:
if (d == "LEFT") snakeX -= box;
if (d == "UP") snakeY -= box;
if (d == "RIGHT") snakeX += box;
if (d == "DOWN") snakeY += box;
您也可以通过转到https://jssnake.glitch.me/并稍作调整来查看此问题。
答案 0 :(得分:2)
我简要查看了您的代码。您每秒渲染10倍,因此,如果您在该间隔内设法按了多个键,则会发生上述问题:
例如,(在向右移动时)按下向上箭头,然后过快地向左箭头键会使我的蛇完全转身并撞向自身,而忽略向上箭头键的按下。
有两种可能的解决方案:
我认为解决方案1并不理想,因为您应该<永>永不言败。因此,让我们继续第3号(hack),然后继续第2号(正确而干净的方式)。
这种小技巧无法解决问题的根源,但是会使蛇的行为表现得很正确。蛇可以向四个方向移动,但始终只能向两个方向旋转。您可以使用两键控制来触发CW / CCW更改,例如
let currentDir = "RIGHT"; //note I renamed your d to currentDir
let nextDir = undefined;
document.addEventListener("keydown", direction);
function direction(event) {
const key = event.keyCode;
while (~currentDir) {}; //wait until the control function is finished
switch (currentDir) {
case "LEFT": nextDir = (key === 37 ? "DOWN" : (key === 39 ? "UP" : nextDir)); break;
case "UP": nextDir = (key === 37 ? "LEFT" : (key === 39 ? "RIGHT" : nextDir)); break;
case "RIGHT": nextDir = (key === 37 ? "UP" : (key === 39 ? "DOWN" : nextDir)); break;
case "DOWN": nextDir = (key === 37 ? "RIGHT" : (key === 39 ? "LEFT" : nextDir)); break;
}
}
//and later in the movement control function:
currentDir = undefined; //avoid overwriting nextDir during this update,
// i.e. the while-loop inside of direction() will wait
switch (tmp) {
case "LEFT": snakeX -= box; break;
case "UP": snakeY -= box; break;
case "RIGHT": snakeX += box; break;
case "DOWN": snakeY += box; break;
}
currentDir = nextDir;
nextDir = undefined;
四键版本将以类似的方式工作,您可以轻松地将其集成到您的代码中。关键是使用currentDir
和nextDir
对,并在两次渲染调用之间的整个0.1秒时间内保持currentDir
不变。但是您的问题会一直存在。仅当您紧接着彼此按下↑和←时,蛇的航向权才会继续向上。
let currentDir = "RIGHT";
let nextDir = undefined;
document.addEventListener("keydown", direction);
function direction(event) {
const key = event.keyCode;
while (~currentDir) {}; //wait until the control function is finished
switch (currentDir) {
case "LEFT":
case "RIGHT":
nextDir = (key === 38 ? "UP" : (key === 40 ? "DOWN" : nextDir)); break;
case "UP":
case "DOWN":
nextDir = (key === 37 ? "LEFT" : (key === 39 ? "RIGHT" : nextDir)); break;
}
}
正确的解决方案更加简单,但是需要一个数组。它将自上次渲染调用以来的所有按键都存储在queue中。
keysPressed = [];
document.addEventListener("keydown", event =>
keysPressed.push(event.keyCode); //enqueues the key pressed
按下两个或三个键,您可以在0.1s间隔内虚拟地更新蛇的位置,每帧有效旋转一圈。如果您能够使用命令快速填充缓冲区,则可能导致蛇移动延迟。尝试一下有趣的锻炼可能会很有趣。四键控件的移动功能如下所示:
{
if (keysPressed.length > 0 {
const key = keysPresses.shift(); //dequeues the oldest key
//if there are more keys in the queue, they have to wait until next time
switch (d) {
case "LEFT":
case "RIGHT":
d = (key === 38 ? "UP" : (key === 40 ? "DOWN" : d)); break;
case "UP":
case "DOWN":
d = (key === 37 ? "LEFT" : (key === 39 ? "RIGHT" : d)); break;
}
}
switch (d) {
case "LEFT": snakeX -= box; break;
case "UP": snakeY -= box; break;
case "RIGHT": snakeX += box; break;
case "DOWN": snakeY += box; break;
}
}
答案 1 :(得分:1)
您这里需要延迟按键的效果。您可以通过将最后按下的键存储在变量中并仅在蛇准备转弯时才读取键来实现。
let pressedKey;
document.addEventListener("keydown", event => {
pressedKey = event.keyCode;
});