9

我开始循环

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. 我每次都必须清理画布吗?不清除它似乎工作得很好。

谢谢。

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

谢谢

4

7 回答 7

8

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);
}

修改后的小提琴在这里

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

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

于 2013-09-25T08:57:28.390 回答
6

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

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

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

now的新版本会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);
}

}

于 2013-09-25T15:25:21.660 回答
2

你应该看看这篇文章,它对这个主题进行了适当的处理。 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 起作用。

于 2014-07-21T04:43:39.107 回答
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);
}
于 2013-09-25T09:12:16.047 回答
0

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

于 2013-12-08T22:42:51.537 回答
0

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

您调整的参数仅适用于 polyfill,如果您的浏览器没有实现requestAnimationFrame.

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

于 2013-09-25T08:58:14.433 回答
0

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

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

于 2013-09-25T08:58:18.260 回答