[我使用强大的requestAnimationFrame(callback)
功能,正在用JavaScript制作游戏。
[今天,我了解到自打开该页面以来,传递给requestAnimationFrame()
的回调获得了高分辨率的时间。我们称它为ms
:
function paint(ms) {
// draw my game
requestAnimationFrame(paint);
}
requestAnimationFrame(paint);
很棒,但是有一件事我不太明白。
功能requestAnimationFrame()
当我们转到另一个选项卡时不执行任何操作,因此渲染暂停。另一方面,离开时传递给回调的时间仍然继续。因此,我不确定如何使用该值。如果它与渲染引擎成比例地工作,我可以使用ms
来计算游戏的逻辑时间,因为依靠requestAnimationFrame()
作为稳定的60 FPS听起来并不是最好的主意。
我想念什么吗?如果ms
参数在离开标签页时继续计数,目的是什么?
这只是一个时间戳,它实际上不算什么。实际上,它实际上与performance.now()
相同,后者给出自页面处于活动状态以来的时间。至于原因,这就是DOMHighResTimeStamp's origin的定义方式。
我们通常使用它来了解自某个先前事件发生以来已经过了多长时间,也就是说,我们存储一个start_time,然后检查当前时间戳,无论实际帧如何,我们都可以获取动画的增量时间-费率。
顺便说一句,不,依靠requestAnimationFrame
以任何固定的帧速率确实不是一个好主意,requestAnimationFrame
不受规格的任何帧速率限制,实际上建议将其对齐屏幕刷新率(尽管只有闪烁)。
因此,实际上,您需要依靠这样的时间戳才能在不同设置之间保持一致的速度。在每帧上执行简单的pos++
可使动画在120Hz监视器上的运行速度比60Hz监视器(至少在Chrome中)快两倍。
这只会使您的想法更复杂,以至于无法理解如何实现:当窗口移至120Hz监视器时,您的绘画计时器会快两倍吗?
此时间戳也可能有助于追上较长的帧,这不是因为系统出现打ic,您不一定希望动画持续更长的时间。同样,并非所有情况都希望窗口模糊时动画逻辑停止。假设我有一个带有由rAF驱动的背景动画的标题,即使不在屏幕上,我也不希望它在屏幕外时显示pause。
如果您希望游戏逻辑在窗口模糊时暂停,请听onvisibilitychange
并保存当前时间戳(由于我们不在rAF之外,请使用onvisibilitychange
。
添加到Kaiido的答案中。在应用程序中限制时间增量也很常见。例如,应用中帧速率独立计算的一种常见方法是计算帧之间的时间
performance.now()
但是,如果let previousTime = 0;
function loop(currentTime) {
const deltaTime = currenTime - previousTime;
previousTime = currentTime;
// use deltaTime in various calculations
posX = posX + velX * deltaTime;
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
太大,有时碰撞和其他数学运算可能会中断,因此游戏经常会添加限制器
deltaTime
这主要消除了检查 // don't let deltaTime be more than a 1/10 of a second
const deltaTime = Math.min(currenTime - previousTime, 1000 / 10);
的需要。特别是如果您保留自己的动画/游戏时钟。
onvisiblitiychange
现在,如果播放器隐藏选项卡,不仅不会跳动,也不会跳动时钟,但是如果我们想暂停,我们可以将let previousTime = 0;
let clock = 0;
let clockRate = 1;
function loop(currentTime) {
const deltaTime = Math.min(currenTime - previousTime, 1000 / 10) * clockRate;
previousTime = currentTime;
clock += deltaTime; // update our own clock
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
设置为0。
为什么要使用自己的时钟?它使您可以轻松降低或加快所有取决于该时钟的计算的时间(请参见上面的clockRate
)。同样,许多应用(游戏)具有多个时钟。他们将为每个时钟计算不同的deltaTime。例如,即使应用程序/游戏已暂停,所有需要暂停的对象的时钟还是时钟都需要继续前进。另一个可能是玩家的时钟与敌人的时钟,因此当玩家使用其“慢时间超级力量”时,敌人的动作变慢,但玩家的动作保持相同的速度。