Javascript - 无法调整FrameRate - requestanimationframe

时间:2013-09-25 08:41:21

标签: javascript html html5 canvas requestanimationframe

我开始循环

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. 我每次都要清理画布吗?没有清除它似乎很好。
  3. 感谢。

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

    由于

7 个答案:

答案 0 :(得分:8)

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

此外,您要改变的是多面填充的后备;也就是说:如果浏览器不支持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运行,但您的代码将执行最少的操作,并且只有当计数器达到其计数时才会执行主代码。

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

答案 1 :(得分:6)

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

注意:requestAnimationFrame现在有更好的处理方式,而不是使用原始3年原始答案中的代码模式...请参阅下面的更新,了解新的改进方法。 < / p>

[更新: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);
}

}

答案 2 :(得分:2)

你应该看看这篇文章,它给出了对这个主题的正确处理。 http://creativejs.com/resources/requestanimationframe/

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

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

答案 3 :(得分:1)

浏览器和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);
}

答案 4 :(得分:0)

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

您调整的参数仅适用于填充,如果您的浏览器未实现requestAnimationFrame,则该填充将处于活动状态。

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

答案 5 :(得分:0)

这就是requestAnimationFrame的工作方式。如果您想要特定的帧率,请仅使用setTimeout

通常你会选择一个参数,即当前时间。将它与最后一帧的时间进行比较,以确定动画应该移动多远。

答案 6 :(得分:0)

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