Javascript基于时间的动画和requestAnimationFrame
我一直在玩Javascript基于时间的动画和requestAnimationFrame,javascript,animation,Javascript,Animation,我一直在玩canvas和动画,特别是HTML5游戏,很快就认识到只使用requestAnimationFrame(rFA)的局限性,并开始使用基于时间的动画 我想保持恒定的游戏性,无论显示器刷新率或FPS,但我不确定如何最好地处理动画。我已经阅读了各种实现,但没有找到任何最佳实践。我应该同时使用这两者吗 到目前为止,我已经考虑了几种选择: rFa仅限(fps更改时更改结果): 仅基于时间(并非始终一致): 使用setInterval在rFA上设置FPS(不总是一致): rFA试图强制fp
canvas
和动画,特别是HTML5游戏,很快就认识到只使用requestAnimationFrame(rFA)
的局限性,并开始使用基于时间的动画
我想保持恒定的游戏性,无论显示器刷新率或FPS,但我不确定如何最好地处理动画。我已经阅读了各种实现,但没有找到任何最佳实践。我应该同时使用这两者吗
到目前为止,我已经考虑了几种选择:
仅限(fps更改时更改结果):rFa
- 仅基于时间(并非始终一致):
- 使用
在setInterval
上设置FPS(不总是一致):rFA
试图强制fps(似乎不太可靠,可变增量效果更好):rFA
- 基于时间的
(一些奇怪的结果):rFA
rFA
进行制表时,仅动画将暂停,使用基于时间的函数调用rFA
意味着游戏/动画将继续在不理想的背景下运行
处理动画的最佳方法是什么?不管fps如何,试图保持一致的结果,以上所有内容都可能不好,我为这篇长文章道歉(这正是我迄今为止尝试过的,但仍然很迷茫)?如果考虑到上述问题,效果会更好?我建议您看看。我不记得这个问题在课程中的实现(但肯定有一个),但从游戏性的角度来看,我的观点是使用rAF(就像你的第一颗子弹)是最有趣的,即使由于较慢的计算机上需要太多的处理而导致游戏速度减慢。我认为您使用上一个游戏的方法是正确的,因为它应该在以不同帧速率运行的设备之间提供最大的一致性,但如果增量太高,您肯定希望强制降低增量值以避免大的跳跃:
var animate = function () {
now = Date.now();
delta = now - last;
last = now;
if(delta > 20) {
delta = 20;
}
draw(delta);
requestAnimationFrame(animate);
};
如果您有可用的
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();
谢谢,我会检查课程的。该解决方案的问题在于,在120Hz的监视器上,游戏的运行速度将是较慢机器的两倍,可能低于预期的60 fps,这意味着游戏的技能水平将发生变化(较慢=更容易反应等)理想情况下,它应该尽可能一致。
draw
和animate
之间有什么区别?他们是干什么的?我想我可以给他们起个更聪明的名字<代码>动画只是下一帧渲染时循环使用的主要功能<代码>绘制将花费时间增量,计算任何对象的新位置/状态,并在每个对象的适当上下文上调用函数<代码>绘制本质上是更新和渲染。啊,我明白了,实际上是有意义的。我只是被“在rFA上用setInterval设置FPS”代码弄糊涂了,这是不正确的。事实上,基于时间的rFA应该可以工作,你得到了什么“奇怪的结果”呢?也许不是抱歉,只是想展示一下这个概念。当fps较低,delta较高时,碰撞检测可能会明显失败,可能正因为如此,物体失去控制(例如错误的轨迹)。更改选项卡也一样,不会真正暂停,只是将delta设置得非常高。正如imcg建议的那样,设置最大增量在这里会有所帮助。另一种解决方案可能是为对象更新单独设置一个循环,独立于动画循环,这样即使帧渲染速度较慢,对象也会定期重新定位?是的,这可能是个好主意。在高fps设备上,在绘制之前进行更新就足够了,如果增量太高,您可能会在绘制之间插入额外的计算,并使用setTimeout
。限制增量值会导致奇怪的同步问题,不是吗?好的,所有内容都应该使用相同的增量时间进行同步。这样做的目的是防止gc等在帧速率上的小幅度下降导致事情在一个步骤中移动过多。为什么会“太多”?而不是保持一个恒定的速度,整个游戏的速度将下降为单一的帧-这感觉比短帧速率下降更笨重。当然,如果帧速率在较长时间内处于较低水平,为了让游戏运行更平稳,你可能需要降低游戏的整体速度。当一次发生太多事情时,往往只是奇怪的帧延迟,然后事情很快恢复正常。使用这种方法,你会有一个小的减速,而没有夹钳,你可以很容易地看到一个精灵突然从屏幕上跳过去(甚至跳下),这充其量是非常刺耳的,最坏的情况下会破坏游戏。
setInterval(function () {
draw();
requestAnimationFrame();
}, 1000/fps);
var delta = 1000 / fps;
var animate = function() {
now = Date.now();
if (now - last >= delta) {
last = now;
}
draw(delta);
requestAnimationFrame(animate);
}
var animate = function () {
now = Date.now();
delta = now - last;
last = now;
draw(delta);
requestAnimationFrame(animate);
}
var animate = function () {
now = Date.now();
delta = now - last;
last = now;
if(delta > 20) {
delta = 20;
}
draw(delta);
requestAnimationFrame(animate);
};
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();