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);
};
感谢您,rAF被锁定为监视器的同步,通常为60 Hz,因此我们无法自行调整FPS(当tab处于非活动状态或使用电池时,浏览器可能会降低FPS) 此外,您试图更改的是多边形填充的后备方案;也就是说:如果浏览器中不支持rAF,它将改为使用
setTimeout
。然而,现在大多数浏览器都支持rAF(甚至不加前缀),因此永远不会使用setTimeout
你可以做两件事:
- 直接使用
替换循环中的rAF(测试时)setTimeout
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好吧,这段代码不是“错误的”而且它确实有效……它只是被更好的功能所取代。我已经更新了我的答案以反映新的功能:-)