Javascript-Can';t调整帧速率-请求动画帧

Javascript-Can';t调整帧速率-请求动画帧,javascript,html,canvas,requestanimationframe,Javascript,Html,Canvas,Requestanimationframe,我开始循环 function gameLoop(){ update(); draw(); requestAnimFrame(gameLoop); } var requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame

我开始循环

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帧。我想这样做只是为了测试的目的
  • 我每次都要清理画布吗?如果不清除它,它似乎工作得很好
  • 谢谢

    以下是完整代码的小提琴链接:


    感谢您,rAF被锁定为监视器的同步,通常为60 Hz,因此我们无法自行调整FPS(当tab处于非活动状态或使用电池时,浏览器可能会降低FPS)

    此外,您试图更改的是多边形填充的后备方案;也就是说:如果浏览器中不支持rAF,它将改为使用
    setTimeout
    。然而,现在大多数浏览器都支持rAF(甚至不加前缀),因此永远不会使用
    setTimeout

    你可以做两件事:

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

    var FPS = 1;
    
    function testLoop() {
    
        ... ordinary code
    
        setTimeout(testLoop, 1000/FPS);
    }
    
    var framesToSkip = 60,
        counter = 0;
    
    function loop() {
    
        if (counter < framesToSkip) {
            counter++;
            requestAnimationFrame(loop);
            return;
        }
    
        /// do regular stuff
    
        counter = 0;
        requestAnimationFrame(loop);
    }
    
    • 使用计数器对rAF进行节流:
    例如:

    var FPS = 1;
    
    function testLoop() {
    
        ... ordinary code
    
        setTimeout(testLoop, 1000/FPS);
    }
    
    var framesToSkip = 60,
        counter = 0;
    
    function loop() {
    
        if (counter < framesToSkip) {
            counter++;
            requestAnimationFrame(loop);
            return;
        }
    
        /// do regular stuff
    
        counter = 0;
        requestAnimationFrame(loop);
    }
    
    var framesToSkip=60,
    计数器=0;
    函数循环(){
    如果(计数器<帧跳过){
    计数器++;
    请求动画帧(循环);
    返回;
    }
    ///做常规的事情
    计数器=0;
    请求动画帧(循环);
    }
    

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


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

    requestAnimationFrame将以最大可实现帧速率(高达60 fps)运行。这是因为它将始终为您提供下一个动画帧

    您调整的参数仅适用于多边形填充,如果您的浏览器没有实现
    requestAnimationFrame
    ,则多边形填充将处于活动状态


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

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


    通常,您需要一个参数,即当前时间。将其与最后一帧的时间进行比较,找出动画应该移动多远。

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

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

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

    下面是一个例子,说明如何更新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);
    }
    

    派对有点晚了,但这里介绍了如何在控制帧数/秒的同时获得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);
    }
    
    var nextTime=0;
    无功延迟=1000;
    函数gameLoop(当前时间){
    
    如果需要在javascript中控制Framrate,那么if(currentTime非常方便的js库

    你应该看看这篇文章,这篇文章对这个主题进行了恰当的处理。


    这是我认为您需要的代码,但在最初的文章中,它说使用了requestAnimationFrame,但我现在使用的是requestAnimationFrame。我想可能它已经更改了,您现在应该使用requestAnimationFrame。requestAnimationFrame对我不起作用,而requestAnimationFrame对我起作用。

    听起来非常合理和聪明。您不应该交换设置超时吗nd requestAnimationFrame?在您的示例中,在setTimeout事件中调用update和draw,在gameloop()主体处于同步状态时仍然是异步的(但除了设置超时外,什么都不做)@DanielAlder。这段代码已经有几年的历史了,现在
    requestAnimationFrame
    自动发送一个时间戳,因此不再需要
    setTimeout
    。使用时间戳来限制动画。当然,但您的代码是错误的。它是在2013年,现在是。@DanielAlder好吧,这段代码不是“错误的”而且它确实有效……它只是被更好的功能所取代。我已经更新了我的答案以反映新的功能:-)