使用requestAnimationFrame在画布上执行更新/绘制循环的正确方法

时间:2013-09-18 08:54:32

标签: javascript canvas coffeescript game-engine

我正在使用<canvas>与JS / Coffeescript进行一场小游戏。

截至目前,我的绘制循环是使用requestAnimationFrame完成的:

draw: () =>
    # Various drawing code.
    requestAnimFrame(@draw, @canvas)

虽然我的更新循环是一个简单的setInterval

setInterval(() => @update Date.now(), 1000/FPS)

我将它们分开,以便绘图不会被不相关的更新代码堵塞,认为这可能是正确的方法。

但是吗?是否有意义?如何以最低的系统成本确保流畅的动画?

1 个答案:

答案 0 :(得分:1)

同时使用requestAnimationFrame(rAF)和setInterval只会产生额外的开销。

这是因为JavaScript是单线程的,必须逐个执行范围。如果JS引擎位于rAF的作用域内,那么setInterval作用域的执行将作为 rAF退出当前作用域后执行的事件排队 - 或者反之亦然。并且代码仍然可能被阻塞/堆叠(由于setInterval)。

所以没有任何好处,恰恰相反,因为有更多的代码要执行(更多有时更少,但在这种情况下不是)包括。内部堆栈推送和弹出,事件的创建和排队,额外的代码解析等 - 可能在微观层面,但它的代码是昂贵的,然后它可能很重要。话虽这么说,考虑使用30 fps而不是60 fps,这在大多数情况下是充足的,它会使你的预算增加一倍。

对于rAF,您的“时间预算”通常约为16.7毫秒。无论你做什么,你都必须得到你需要的代码来创建一个在该时间范围内执行的帧。如果不是,则跳过一帧(或更多)。

关键是优化代码以及如何将场景组合在一起,无论是字面还是抽象。尽可能缓存所有内容(内存是你的朋友),只更新所需内容等等。对此没有通用的答案,因为它取决于具体情况,最佳的做事方式是什么。