【问题标题】:Javascript - Can't Adjust FrameRate - requestanimationframeJavascript - 无法调整 FrameRate - requestanimationframe
【发布时间】:2013-09-30 18:16:04
【问题描述】:

我开始循环

function gameLoop(){
   update();
   draw();
   requestAnimFrame(gameLoop);
}

var requestAnimFrame =  window.requestAnimationFrame ||
                    window.webkitRequestAnimationFrame ||
                    window.mozRequestAnimationFrame ||
                    window.oRequestAnimationFrame ||
                    window.msRequestAnimationFrame ||
                    function(callback) {
                        window.setTimeout(callback, 1000 / 1);
                    };
  1. 我无法调整帧频。它总是非常快。为什么我不能将其更改为每秒 1 帧。我想这样做只是为了测试。
  2. 是否每次都必须清除画布?不清除它似乎也能正常工作。

谢谢。

这是完整代码的小提琴链接: complete code

谢谢

【问题讨论】:

    标签: javascript html canvas requestanimationframe


    【解决方案1】:

    聚会有点晚了,但这里是如何在控制帧/秒的同时获得 RAF 的好处。

    注意:requestAnimationFrame 现在有比使用我原来 3 年的原始答案中的代码模式更好的做事方式......请参阅下面的更新以了解新的和改进的方式。

    [更新:requestAnimationFrame 现在有更好的节流方式]

    requestAnimationFrame 的新版本现在会自动发送当前时间戳,您可以使用该时间戳来限制代码执行。

    这是每 1000 毫秒执行一次代码的示例代码:

    var nextTime=0;
    var delay=1000;
    
    function gameLoop(currentTime){
        if(currentTime<nextTime){requestAnimationFrame(gameLoop); return;}
        nextTime=currentTime+delay;
        // do stuff every 1000ms
        requestAnimationFrame(looper);
    }
    

    }

    【讨论】:

    • 听起来非常合乎逻辑和聪明。
    • 你不应该以某种方式交换 setTimeout 和 requestAnimationFrame 吗?在您的示例中,在 setTimeout 事件中调用 update 和 draw,在 gameloop() 主体同步时仍然异步(但除了设置超时之外什么都不做)
    • @DanielAlder。此代码已有几年历史,现在requestAnimationFrame 自动发送时间戳,因此不再需要setTimeout。使用时间戳来限制动画。
    • 当然可以,但是您的代码还是错误的。那是在 2013 年,现在是。
    • @DanielAlder 好吧,这段代码没有“错误”,它确实有效......它只是被更好的功能所取代。我已经更新了我的答案以反映新功能:-)
    【解决方案2】:

    requestAnimationFrame 将以可实现的最大帧速率(最高 60 fps)运行。这是因为它总是会给你下一个动画帧。

    您调整的参数仅适用于polyfill,如果您的浏览器没有实现requestAnimationFrame,它将处于活动状态。

    如果您想尝试在一秒钟内进行绘画以进行测试,请改用setInterval

    【讨论】:

      【解决方案3】:

      您应该查看这篇文章,该文章对该主题进行了适当的处理。 http://creativejs.com/resources/requestanimationframe/

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

      这是我认为你想要的代码,但在原始文章中它说使用 requestAnimationFrame,但这里我使用的是 requestAnimFrame。我想也许它改变了,你现在应该使用 requestAnimFrame 。 requestAnimationFrame 对我不起作用,而 requestAnimFrame 起作用。

      【讨论】:

        【解决方案4】:

        raf被锁定到监控的同步,通常为60 hz,因此我们无法自行调整FPS(当浏览器可能会在电池时或电池上减少FPS)。

        此外,您要更改的是 poly-fill 的后备;也就是说:如果浏览器不支持 rAF,它将使用setTimeout。然而,现在大多数浏览器确实支持 rAF(甚至没有前缀),所以setTimeout 永远不会被使用。

        你可以做两件事:

        • 直接使用setTimeout 替换循环中的rAF(测试时)

        例子:

        var FPS = 1;
        
        function testLoop() {
        
            ... ordinary code
        
            setTimeout(testLoop, 1000/FPS);
        }
        
        • 使用计数器限制 rAF:

        例子:

        var framesToSkip = 60,
            counter = 0;
        
        function loop() {
        
            if (counter < framesToSkip) {
                counter++;
                requestAnimationFrame(loop);
                return;
            }
        
            /// do regular stuff
        
            counter = 0;
            requestAnimationFrame(loop);
        }
        

        MODIFIED FIDDLE HERE

        很可能有更好的方法来实现限制,但我只是想展示基本原理。这仍然会以 60 FPS 的全速运行,但您的代码将执行最少的操作,并且只有当计数器达到其计数时,它才会执行主代码。

        如果您接下来绘制的内容将覆盖之前绘制的内容,或者您​​当然想保留它,则无需每次都清除画布。如果需要,您还可以清除一部分以进一步优化。

        【讨论】:

          【解决方案5】:

          如果您需要在 javascript 中控制 Framrate,非常方便的 js 库 https://github.com/aaronGoshine/Javascript-OnEnterFrame-Event-Manager/blob/master/index.html

          【讨论】:

            【解决方案6】:

            浏览器和 javascript 的工作方式使得设置固定帧速率变得困难。假设你想每一秒都做一些事情,比如更新和绘图。一种方法是调用window.setTimeout(),设置为一秒。但问题是这不是那么可靠,即使您每秒配置一次回调,您也不能确定所有回调都会及时。例如,高处理器负载可能会使回调到达的时间比应有的晚得多。即使回调会准时,您也无法控制实际绘制到屏幕的时间。

            更好的处理方法是接受这样一个事实,即您无法获得非常精确的通话时间,相反,每当您接到电话时,您都会计算过去了多少时间并据此采取行动。这意味着您将让系统决定帧速率,您只需根据经过的时间来更新动画或游戏。

            requestAnimationFrame 是目前大多数浏览器都支持的新功能,对游戏特别有用。每次浏览器准备好绘制时都会调用它,这很好。然后你就会知道你正在做的更新和绘图将在实际帧被绘制到屏幕之前发生。

            这是一个示例,说明如何更新 gameLoop 以将时差考虑在内。

            var lastTimestamp = +new Date;
            
            function gameLoop(timestamp) {
              var now = +new Date;
              var dt = now - lastTimestamp;
            
              // dt is the amount of time in ms that has passed since last call.
              // update takes this time difference (in seconds) and can then perform its
              // updates based on time passed.
              update(dt / 1000);
              draw();
              lastTimestamp = now;
              requestAnimationFrame(gameLoop);
            }
            

            【讨论】:

              【解决方案7】:

              requestAnimationFrame 就是这样工作的。如果您需要特定的帧速率,请仅使用 setTimeout

              通常你会带一个参数,即当前时间。将其与上一帧的时间进行比较,以了解动画应该移动多远。

              【讨论】:

                猜你喜欢
                • 2013-10-27
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-01-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多