如何阻止蛇沿对角线移动



我正在用JavaScript开发Snake游戏,我希望Snake只垂直或水平移动,但它一直沿对角线移动。例如,如果我向上按,它会向上移动,但如果我向右按,它将沿对角线移动,而不仅仅是向右移动。

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const length_width = 15;
let snakeCoord = [
{x:300,y:150},
{x:315,y:150},
{x:330,y:150},
{x:345,y:150},
{x:360,y:150},
{x:375,y:150}
]; 
function drawSnakePart(snakePart) {
ctx.beginPath();
ctx.fillRect(snakePart.x, snakePart.y, length_width, length_width);
ctx.strokeRect(snakePart.x, snakePart.y, length_width, length_width);
ctx.closePath();
}
function drawSnake() {
snakeCoord.forEach(drawSnakePart);
}
function moveSnake(dx, dy) {
const head = {
x: snakeCoord[0].x + dx,
y: snakeCoord[0].y + dy
};
snakeCoord.unshift(head);
snakeCoord.pop();
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawSnake();
setTimeout(function() {
moveSnake(dx, dy)
}, 100);
}
function keyPress(e) {
let key = e.key;
if (key == "ArrowUp") {
if (snakeCoord[0].y - length_width !== snakeCoord[1].y) {
moveSnake(0, -length_width);
}
} else if (key == "ArrowDown") {
if (snakeCoord[0].y + length_width !== snakeCoord[1].y) {
moveSnake(0, length_width);
}
} else if (key == "ArrowLeft") {
if (snakeCoord[0].x - length_width !== snakeCoord[1].x) {
moveSnake(-length_width, 0);
}
} else if (key == "ArrowRight") {
if (snakeCoord[0].x + length_width !== snakeCoord[1].x) {
moveSnake(length_width, 0);
}
}
}
drawSnake();
document.addEventListener("keyup", keyPress);
<canvas width="500" height="500"></canvas>

每次按键,然后递归地设置新的超时setTimeout(function(){ moveSnake(dx,dy) }, 100);。您最终会遇到越来越多的有冲突的moveSnake调用。

您应该将超时保存到一个变量中,并在调用moveSnake()之前用键盘上的clearTimeout()清除它。

与其让键盘处理程序调用一个启动自己定时器循环的move方法,不如使用一个update例程来更新一帧动画的所有内容。您还应该使用requestAnimationFrame以尽可能快的速度驱动渲染,并使每个渲染请求都具有下一个动画帧。(请参阅提供的链接中的示例。)如果您想要较慢的动画,则可以使用单独的计时器逐步更新场景。(相信我,总有一天你会想要高帧率的动画,即使是在循序渐进的游戏中。)

我很无聊,所以我决定对您的代码进行一些更改。

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const length_width = 15;
let snakeCoord = [
{x:300,y:150},
{x:315,y:150},
{x:330,y:150},
{x:345,y:150},
{x:360,y:150},
{x:375,y:150}
]; 
let snake = {
dir: {dx: -1, dy: 0},
nextDir: [], // buffered direction changes
speed: 5, // steps per second
ratchet: 0
};
function drawSnakePart(snakePart) {
ctx.beginPath();
ctx.fillRect(snakePart.x, snakePart.y, length_width, length_width);
ctx.strokeRect(snakePart.x, snakePart.y, length_width, length_width);
ctx.closePath();
}
function drawSnake() {
snakeCoord.forEach(drawSnakePart);
}
function moveSnake() {
if (snake.nextDir[0]) {
// only change directions if it doesn't result in doubling back on yourself
if (snakeCoord[0].x + snake.nextDir[0].dx * length_width !== snakeCoord[1].x
&& snakeCoord[0].y + snake.nextDir[0].dy * length_width !== snakeCoord[1].y) {
snake.dir = snake.nextDir[0];
}
snake.nextDir.shift(1);
}
const head = {
x: snakeCoord[0].x + snake.dir.dx * length_width,
y: snakeCoord[0].y + snake.dir.dy * length_width
};
snakeCoord.unshift(head);
snakeCoord.pop();
}
function keyPress(e) {
let key = e.key;
if (key == "ArrowUp") {
setDirection(0,-1);
} else if (key == "ArrowDown") {
setDirection(0, 1);
} else if (key == "ArrowLeft") {
setDirection(-1, 0);
} else if (key == "ArrowRight") {
setDirection(1, 0);
}
e.preventDefault();
}
drawSnake();
let lastTime = new Date();
window.requestAnimationFrame(render);
function setDirection(dx, dy) {
snake.nextDir.push({dx, dy}); // overwrite any pending direction changes.
}
function update() {
let now = Date.now();
let elapsed = (now - lastTime) / 1000;
snake.ratchet += elapsed * snake.speed;
while (snake.ratchet >= 1) {
moveSnake();
snake.ratchet -= 1;
}
lastTime = now;
}
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
drawSnake();
window.requestAnimationFrame(render);
}
document.addEventListener("keydown", keyPress);
* {
overflow: hidden
}
<canvas width="500" height="500"></canvas>

使其成为高帧速率渲染循环。采用棘轮机制,每隔一段时间以一定的速度离散地移动蛇(参见snake.speed)。添加了蛇的一个特性,即它的方向。(请参阅snake.dir)。请求的方向更改的缓冲击键(请参阅snake.nextDir)简化了防止蛇自行加倍的逻辑。每移动一步,吃掉一个方向变化。

你仍然需要做蛇的自我碰撞。(假设这就是你所做的,使用传统的蛇游戏。)

不管怎样,我希望这对你或其他人有帮助。

最新更新