在游戏关卡结束时退出 setInterval

escape from setInterval at end of game level

我正在使用 HTML5 canvas 和 Javascript 编写游戏。我正在使用 setInterval 来设置游戏动画并定期检查事件。我已经为游戏编写了多个级别,但是当给定级别结束以开始下一个级别时,我似乎无法逃避 setInterval 。代码准确地检测到一个级别何时获胜或失败,并成功清除间隔并呈现按钮,但按钮没有触发。

添加按钮是我的最新想法。我还尝试使用 jQuery 删除 canvas 并插入一个新的。我也试过在 canvas 上使用 clearRect,但它也没有触发。

鉴于我无法 return 来自 setInterval 的值,我有什么选择(如果有)?还有另一种方法可以完成同样的事情吗?我的代码是否存在我忽略的单独错误?谢谢!

Game.prototype.win = function(int) {
    clearInterval(int);
    var content = "<p style='color:white;'>You win</p><br><button id='next-level'>Next Level</button></menu>"
    $('#controls').append(content)
};

Game.prototype.lose = function(int) {
    clearInterval(int);
    var content = "<p style='color:white;'>You Lose</p><br><button id='next-level'>Start Over?</button></menu>"
    $('#controls').append(content)
};

Game.prototype.run = funtion () {    
    $('#start').click( function () {
      $('#controls').empty();
      var waveOne = new window.CrystalQuest.Wave(this.X_DIM, this.Y_DIM, this, Game.WAVE_ONE)
      var game = this

      var int = setInterval( function () {
        if (waveOne.step() === "lost" ) {
          game.lose(int);
        } else if (waveOne.step() === "won") {
          game.win(int);
        }
        waveOne.draw(this.ctx)
      }, 20)
      this.bindKeyHandlers(waveOne);
   }.bind(this));

   $('#next-level').click( function () {
      $('#controls').empty();
      ...more code...
   });
};

要停止 setInterval(),您必须将对 setInterval() 的原始调用的返回值存储在某个持久位置,然后对该值调用 clearInterval()

因为您在 var int 中使用 var 声明了间隔,所以它仅适用于该方法,在代码的其他任何地方都不可用。

在您的代码中有多种方法可以做到这一点。我可能会建议将其存储为这样的实例变量:

Game.prototype.run = funtion () {    
    $('#start').click( function () {
      $('#controls').empty();
      var waveOne = new window.CrystalQuest.Wave(this.X_DIM, this.Y_DIM, this, Game.WAVE_ONE)
      var game = this;

      this.stop();
      this.interval = setInterval( function () {
        if (waveOne.step() === "lost" ) {
          game.lose(int);
        } else if (waveOne.step() === "won") {
          game.win(int);
        }
        waveOne.draw(this.ctx)
      }, 20)
      this.bindKeyHandlers(waveOne);
   }.bind(this));

   $('#next-level').click( function () {
      $('#controls').empty();
      ...more code...
   });
};

然后,你可以创建一个停止间隔的方法,如下所示:

Game.prototype.stop = function() {
      if (this.interval) {
          clearInterval(this.interval);
          this.interval = null;
      }
}

然后,像这样更改您的其他方法:

Game.prototype.win = function(int) {
    this.stop();
    var content = "<p style='color:white;'>You win</p><br><button id='next-level'>Next Level</button></menu>"
    $('#controls').append(content)
};

Game.prototype.lose = function(int) {
    this.stop();
    var content = "<p style='color:white;'>You Lose</p><br><button id='next-level'>Start Over?</button></menu>"
    $('#controls').append(content)
};

对于您的事件处理问题,如果您正在销毁并重新创建一个按钮,那么您将丢失附加到任何被替换的 DOM 元素的任何事件处理程序。

您有两种修复方式可供选择:

  1. 创建新的 DOM 元素后,您可以再次在新的 DOM 元素上设置事件处理程序。
  2. 您可以使用 "delegated event handling"。这会将事件处理程序附加到本身未被替换的父 DOM 对象。单击事件冒泡到父级并在那里处理。可以根据需要多次替换子项,事件处理程序仍然有效。

请参阅这些参考资料,了解如何通过 jQuery 使用委托事件处理:

Does jQuery.on() work for elements that are added after the event handler is created?

jQuery .live() vs .on() method for adding a click event after loading dynamic html

JQuery Event Handlers - What's the "Best" method