Javascript基于时间的动画和requestAnimationFrame

Javascript time-based animation and requestAnimationFrame

本文关键字:动画 requestAnimationFrame 时间 于时间 Javascript      更新时间:2023-09-26

我一直在玩canvas和动画,特别是在HTML5游戏中,很快就学会了只使用requestAnimationFrame (rFA)的局限性,并转向了基于时间的动画。

无论显示器刷新率或FPS如何,我都想保持恒定的游戏玩法,但我不确定如何最好地处理动画。我已经通读了各种各样的实现,但还没有找到任何最佳实践。我应该使用两者的组合吗?

到目前为止,我考虑了几个选项:

  • rFa(当fps改变时改变结果):

    var animate = function() {
         draw();
         requestAnimationFrame(animate);
    }
    
  • 仅基于时间(不总是一致):

    var animate = function() {
        now = Date.now();
        delta = now - last;
        last = now;
        draw(delta);
        window.setTimeout(animate, 1000/60)
    }
    
  • 设置rFAsetInterval的FPS(不总是一致):

    setInterval(function () {
        draw();
        requestAnimationFrame();
    }, 1000/fps);
    
  • rFA试图强制fps(似乎不是很健壮,变量delta会更好):

    var delta = 1000 / fps;
    var animate = function() {
       now = Date.now();
       if (now - last >= delta) {
           last = now;
        }
        draw(delta);
        requestAnimationFrame(animate);
    }
    
  • 基于时间的rFA(一些奇怪的结果):

    var animate = function () {
        now = Date.now();
        delta = now - last;
        last = now;
        draw(delta);
        requestAnimationFrame(animate);
    }
    

忽略缺乏浏览器支持和Date.now()的使用,我只是想演示我的思维流程。我认为最后一个选项是可取的,但最后两个可能会遇到更新太远,缺少碰撞等问题,以及更新时间太长,动画失去了所有控制。

同样,当用户使用rFA选项卡退出时,动画将暂停,使用基于时间的函数调用rFA意味着游戏/动画将继续在后台运行,这是不理想的。

什么是最好的方法来处理动画,试图保持一致的结果,不管fps,所有以上可能是坏的,我的长帖子道歉(这只是我已经尝试到目前为止,我仍然相当迷路)?考虑到上述问题会更好吗?

如果您有requestAnimationFrame可用,我不会反对它,只从其回调中调用draw()。当然,您应该始终使用增量计时。

这是raF的复杂变体,在帧率太低的情况下,游戏逻辑更新会退回到setTimeout:

var maximalUpdateDelay = 25; // ms
var updateTimeout, now;
function animate() {
    updateTimeout = setTimeout(animate, maximalUpdateDelay);
    var delta = -now + (now = Date.now());
    update(now, delta);
}
function main() {
    clearTimeout(updateTimeout);
    animate(); // update the scene
    draw(); // render the scene
    requestAnimationFrame(main);
}
main();

我建议你看看Udacity上的HTML 5 -游戏开发课程。我不记得这个问题在课程中的实现(但肯定有一个),但从游戏玩法的角度来看,我的观点是使用rAF(就像你的第一颗子弹)是最有趣的,即使由于在较慢的计算机上需要太多处理而导致游戏变慢。

我认为你的最后一项选择是正确的,因为它应该给你在不同设备上运行的一致性,但如果它太高,你肯定想强迫你的delta值降低,以避免大的跳跃:

var animate = function () {
    now = Date.now();
    delta = now - last;
    last = now;
    if(delta > 20) {
        delta = 20;
    }
    draw(delta);
    requestAnimationFrame(animate);
};