【问题标题】:requestAnimationFrame isn't canceledrequestAnimationFrame 没有被取消
【发布时间】:2013-08-15 14:11:06
【问题描述】:

我正在开发一个使用 requestAnimationFrame 的游戏。这是它的代码。

Game.prototype.startLoop = function (arg) {

    var parent = this;

    (function tick() {

        parent.update();
        window.animationID = webkitRequestAnimationFrame(tick);

    }());

};

Game.prototype.stopLoop = function () {
    console.log('cancel the game now');
    window.webkitCancelRequestAnimationFrame(window.animationID);
};

问题是我收到了消息cancel the game now,但是游戏继续运行,因为 animationFrame 不知何故没有被取消。我试过webkitCancelAnimationFramecancelAnimationFramewebkitCancelRequestAnimationFrame,以及在我的浏览器中请求动画帧的所有版本:requestAnimationFramewebkitRequestAnimationFrame。这些组合都不起作用。

奇怪的是,如果我在 webkit 检查器控制台中运行window.webkitCancelRequestAnimationFrame(window.animationID),游戏会按预期停止。我将此代码 window.webkitCancelRequestAnimationFrame(window.animationID); console.log('button test') 添加到 DOM 按钮的 onclick 属性中,当我单击它时游戏停止,但是当我执行 JS theDOMButton.click() 时没有任何反应,但我确实收到消息“按钮测试”。

这是我的用户代理:

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36

这是一个 jsfiddle:

http://jsfiddle.net/mJPMt/

更改为:http://pastebin.com/ewDXBT9C 后它可以工作,但我认为这很奇怪,因为请求动画应该停止而不需要在每个循环中检查变量

【问题讨论】:

  • 首先,使用 shim/polyfill。你的代码会破坏所有不是 webkit 的东西。
  • 谢谢,但我正在使用 webkit,所以现在不需要 pollyfills,他们不会对我的问题做任何事情。
  • 您能否将您拥有的代码简化为一个可以重现问题的小测试 - 最好将其发布为小提琴?很有可能是其他一些互动导致了问题。
  • 您也可以尝试更改逻辑以在请求下一个动画帧之前检查布尔值。看看这是否会以任何方式改变行为会很有趣。 if(!stopped) webkitRequestAnimationFrame(tick)

标签: javascript animation html5-canvas


【解决方案1】:

设置id后需要调用update

(function tick () {
    id = webkitRequestAnimationFrame(tick);
    update();
}());

否则它会停止旧的,但新的仍在设置中。

FIDDLE

要解决 Vincent Piel 提出的问题,您可以随时使用 update,例如 promise。这是使用这种方法的fiddle。它与他的回答中的类似,只是您不需要范围布尔值。

function update() {
    var dfd = $.Deferred();
    x += 0.1;
    y += 0.1;

    if (x > 50) {
        dfd.reject();
        return;
    }

    draw();
    dfd.resolve();

    return dfd.promise();
}

(function tick () {
    update().done(function() {
        id = webkitRequestAnimationFrame(tick);
    });
}());

【讨论】:

  • 如果更新持续时间过长,则会出现问题:在上次更新结束之前会调用另一个更新。在长时间更新和高刷新率(例如 120Hz)的情况下,它可能真的会发生,尤其是当邪恶的垃圾收集器暂停更新时。
  • @VincentPiel 我更新了我的答案以包含另一个绝对不会有这个问题的可能解决方案。
【解决方案2】:

您看到的行为完全正常:发生的情况是您在 update() 方法中完成了取消操作。
因此,您实际上取消的是以前的 rAF,并且无论更新中发生了什么,您都会启动另一个rAF。

(function tick() {

    parent.update(); // here we cancel the last window.animationID
    window.animationID = rAF(tick); // here we go again, we launch another rAF

}());

当您在控制台中执行此操作时,您将取消 next rAF,因此游戏停止。

因此,您需要使用布尔值来停止循环,甚至不保存动画 ID。

我不知道你想如何处理这个布尔值(闭包/命名空间/全局变量),但它看起来像:

var animCancelled = false;
(function tick() {

    parent.update(); 
    if (!animCancelled) rAF(tick); 

}());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 1970-01-01
    相关资源
    最近更新 更多