我们都知道如果某些fps很重要或类似的话,制作正确的更新算法是多么困难。
无论如何,我只是想出了这个无限循环的循环黑客,它只是将程序冻结到下一帧,它似乎完美无缺。
var then = Date.now()
var fps = 40;
var interval = 1000 / fps;
function mainloop() {
while (Date.now() - then < interval) {} // freezes program until next frame
requestAnimationFrame(mainloop);
then = Date.now();
// update logic goes here
}
mainloop();
我还没有在任何地方看到这个解决方案,所以我想问一下它是否干净正确。我知道冻结程序只是为了等待某些东西并且那段代码看起来很糟糕,但它似乎有效。是否有一个更清洁的解决方案与我的代码类似?
答案 0 :(得分:0)
在您的特定场景中,使用setTimeout延迟mainloop执行可能会更好,如下所示:
var nextExecution = Date.now() - then + interval;
if (nextExecution < 0) nextExecution = 0;
setTimeout(mainloop, nextExecution);
这将允许它在等待下一帧渲染时执行其他操作。
答案 1 :(得分:0)
使用while循环浪费时间是一个坏主意。它只会浪费处理器时间,可能会做其他事情。
使用jishi建议的SetTimeout是一种可能的解决方案。但是,这仅控制代码运行的时间。您无法真正控制浏览器实际绘制的时间。基本上,浏览器将绘制代码更新的最后一帧。
因此,另一种可能的解决方案是使用requestAnimation。在您的绘图代码中,确定以您的首选费率发生的最后一帧。绘制那个框架。例如......
var start = null;
var fps = 40;
var interval = 1000 / fps;
function mainloop(timeStamp) {
if (!start) {
start = timeStamp;
}
var n = (timeStamp - start) / interval;
// update logic goes here to paint nth frame
requestAnimationFrame(mainloop);
}
mainloop();
答案 2 :(得分:0)
您可以使用setTimeout等待一段时间,但这不会非常精确。但是,通过一直更改interval
,您可以获得足够精确的平均延迟。
var startTime = Date.now();
var fps = 40;
var frames = 0;
var interval = 1000 / fps;
function mainloop() {
frames++;
var timeElapsed = Date.now() - startTime,
averageFps = 1000 * frames / timeElapsed;
if(averageFps < fps && interval > 0) interval -= 0.1;
if(averageFps > fps) interval += 0.1;
setTimeout(mainloop, interval);
// update logic goes here
}
setTimeout(mainloop, interval);
但如果计算机太慢,计算机仍然无法满足请求的fps。