我使用javascript画布制作了经典的Snake街机游戏,并且我尝试构建内置功能以减小游戏动画的运行间隔。如果您不熟悉Snake,则蛇会在屏幕上四处移动,并尝试吃掉随机出现的苹果,同时尽量不碰到自己或墙壁。蛇每次吃一个苹果,它的大小就会变长,游戏也会变得更加困难。我试图通过每次蛇吃一个苹果时加快游戏速度来增加游戏难度。我已经在下面的代码片段中实现了这一点:

//Animate the game
function gameLoop() {
  ctx.clearRect(0, 0, width, height);
  drawScore();
  snake.move();
  snake.draw();
  apple.draw();
  drawBorder();
  var timeoutID = setTimeout(function() {
    gameLoop();
  }, interval);
};
gameLoop(); //call the game loop


问题是我有一个gameOver()函数可以访问运行游戏的timeoutId函数的setTimeout,但是timeoutId变量未在gameOver()函数中定义。为了使事情更加混乱,gameOver函数在预期的时候仍然可以工作,但是会在控制台中产生一个错误,提示:

Uncaught ReferenceError: timeoutID is not defined
    at gameOver (snake.html:68)
    at Snake.move (snake.html:157)
    at gameLoop (snake.html:253)
    at snake.html:258


并且gameOver()函数未按预期运行。它应该显示“游戏结束”并显示玩家的最后得分,并简单地显示未做出的蛇。相反,当调用gameOver()函数时,它将擦除屏幕。这是gameOver()函数:

function gameOver() {
  ctx.font = "60px monospace";
  ctx.fillStyle = "black";
  ctx.textAlign = "center";
  ctx.fillText("Game Over", width/2, height/2);
  clearTimeout(timeoutID);
};


我想知道是否有一种方法可以在游戏结束时停止gameLoop()功能,而不会收到错误消息且不会擦除屏幕。我尝试了几种不同的方法都没有用。谢谢。

最佳答案

您需要在timeoutID之外定义gameLoop,以便在其他位置可见,例如gameOver函数:

var timeoutID;
function gameLoop() {
  // ...
  timeoutID = setTimeout( ...
  // ...
}
// ...
function gameOver() {
  // referencing timeoutID here will now be possible


但是在这种情况下,与保存timeoutID相比,您可能会发现,简单地使用一个外部布尔值指示gameLoop是否应该运行,会容易一些:

var gameIsOver = false;
function gameLoop() {
  if (gameIsOver) return;
  // ...
}
// ...
function gameOver() {
  gameIsOver = true;
  // ...

关于javascript - 如何在多个作用域中定义timeoutId,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51014207/

10-10 00:11