【问题标题】:HTML Canvas Interval vs RequestAnimationFrameHTML 画布间隔与 RequestAnimationFrame
【发布时间】:2014-02-13 12:45:24
【问题描述】:

所以,这里可能完全是脑残。 setInterval() 的语法非常清晰。每 x 毫秒做一些事情。如何最好地使用requestAnimationFrame() 翻译?

我有大约 300 个对象,每个对象都应该以一定的间隔(每 8、6、2 等秒)执行动画序列?我怎样才能最好地使用requestAnimationFrame() 来实现这一点,它每秒被调用约 60 次?可能有一个简单的答案,我只是,为了我的一生,无法弄清楚。

【问题讨论】:

    标签: javascript canvas html5-canvas


    【解决方案1】:

    要强制 requestAnimationFrame 坚持特定的 FPS,您可以同时使用两者!

    var fps = 15;
    function draw() {
        setTimeout(function() {
            requestAnimationFrame(draw);
            // Drawing code goes here
        }, 1000 / fps);
    }
    

    有点奇怪,但不是世界上最令人困惑的事情。

    您也可以使用 requestAnimationFrame 而不是 FPS,而是使用经过的时间,以便根据自上次调用以来的时间差绘制需要更新的对象:

    var time;
    function draw() {
        requestAnimationFrame(draw);
        var now = new Date().getTime(),
            dt = now - (time || now);
     
        time = now;
     
        // Drawing code goes here... for example updating an 'x' position:
        this.x += 10 * dt; // Increase 'x' by 10 units per millisecond
    }
    

    这两个 sn-ps 来自 this fine article,其中包含更多详细信息。

    顺便问下好问题!我想我也没有在 SO 上看到这个答案(而且我在这里太多了)

    【讨论】:

    • 另外,谢谢!第二个 sn-p 接近我所追求的。正如我在第一个答案的评论中所说,这似乎是我所追求的:gist.github.com/1002116
    • 两个答案都非常棒 - 非常感谢!
    • requestAnimationFrame 发送时间戳作为参数。根据我的经验,创建一个新的 Date 对象比使用提供的时间戳要昂贵得多。
    • 是的,出于性能原因,您应该避免在循环中创建新的日期对象(或任何新对象),但 mozAnimationStartTime 仅在 Firefox 上可用,我不知道任何其他浏览器实现了提供时间戳。
    • 时间戳是我不知道的一个有趣的花絮。那么,到目前为止,它是 Mozilla 的实现所独有的吗?
    【解决方案2】:

    requestAnimationFrame 是相当低的级别,它只是做了你已经说过的事情:大约以 60fps 的速度被调用(假设浏览器可以跟上那个速度)。因此,通常您需要在此基础上构建一些东西,就像具有游戏循环的游戏引擎一样。

    在我的游戏引擎中,我有这个(在此处进行解释/简化):

    window.requestAnimationFrame(this._doFrame);
    
    ...
    
    _doFrame: function(timestamp) {
         var delta = timestamp - (this._lastTimestamp || timestamp);
    
         for(var i = 0, len = this.elements.length; i < len; ++i) {
             this.elements[i].update(delta);
         }
    
         this._lastTimestamp = timestamp;
    
         // I used underscore.js's 'bindAll' to make _doFrame always
         // get called against my game engine object
         window.requestAnimationFrame(this._doFrame);
     }
    

    然后我的游戏引擎中的每个元素都知道如何更新自己。在您的情况下,应该每 2、6、8 秒更新一次的每个元素都需要跟踪已经过去了多少时间并相应地更新:

    update: function(delta) {
         this.elapsed += delta;
    
         // has 8 seconds passed?
         if(this.elapsed >= 8000) {
              this.elapsed -= 8000;  // reset the elapsed counter
              this.doMyUpdate(); // whatever it should be
         }
     }
    

    Canvas API 和 requestAnimationFrame 是相当低级的,它们是动画和游戏引擎之类的构建块。如果可能的话,我会尝试使用现有的,如 cocos2d-js 或这些天来的其他任何东西。

    【讨论】:

    • 谢谢!这几乎就是我所追求的。更多挖掘揭示了这一点:gist.github.com/1002116 这基本上就是你所拥有的。我认为我的错误是试图让它在一个主循环中而不是每个对象的循环中工作。
    猜你喜欢
    • 1970-01-01
    • 2019-05-08
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    相关资源
    最近更新 更多