有没有办法为 high/low 不在 60hz 的帧率监视器设置 rAF 的 FPS?
Is there a way to set FPS for rAF for high/low frame rate monitors not on 60hz?
所以我有一台 120hz 显示器和一台 60hz 显示器。如果我 运行 我的游戏在第一个显示器上,它 运行 非常快,但是当我 运行 在第二个显示器上时,它会变慢。而且我知道那里也有很多 30hz 显示器,速度会更慢(还有一点点 240hz 显示器,速度快如闪电)。有什么方法可以将游戏的帧率锁定在 60fps(这是最常见的),这样问题就不会发生了?
不,requestAnimationFrame
应该在下一次屏幕刷新之前触发,这使其与屏幕刷新率相关联。
你需要的是 delta-time.
不是在每个滴答时按静态值增加对象位置,而是测量自上次滴答以来的时间,并根据经过的时间和预设持续时间更新您的值。
这样,无论显示器的刷新率如何,或者即使页面受到计算机等的限制,您的动画对象也会以相同的速度在任何地方行走给定的距离。
这里是一个例子,显示即使我们“暂停”动画,当我们“恢复”它时,对象也会在没有暂停的情况下应该在的位置。
const it = document.getElementById( "it" );
const checkbox = document.querySelector( "input" );
const maxLeft = window.innerWidth - 50;
const duration = 2000; // time to traverse the screen (ms)
const start = performance.now();
function anim( now ) {
// 'now' passed by rAF is the time the last VSync event has been sent by the monitor
// it may not be the real "now" time, for this one could use
// performance.now() instead
const delta = ((now - start) % duration) / duration;
// determine if we should go to left or to right
const direction = Math.sign( ((now - start) % (duration * 2)) - duration );
let position;
if( direction < 0 ) {
position = delta * maxLeft;
}
else {
position = maxLeft - (delta * maxLeft);
}
it.style.transform = `translateX(${ position }px)`;
if( checkbox.checked ) {
requestAnimationFrame( anim );
}
}
requestAnimationFrame( anim );
checkbox.oninput = anim;
#it {
width: 50px;
height: 50px;
background: red;
border-radius: 50%;
position: fixed;
top: 50px;
will-change: transform;
}
<div id="it"></div>
<label>pause/resume<input type="checkbox" checked></label>
Kaiido 的方法非常适合简单的动画和游戏,但如果您需要更复杂的功能,还可以采用其他一些方法。
假设某种操作每秒需要发生 n
次;我们称之为滴答声。一种方法是让 requestAnimationFrame
以及 setInterval
用于可能需要在帧之间发生的任务。例如:
var tick_rate = 50; // This is the ideal number of ticks per second
function draw_frame(now) {
// This code only handles the graphics
requestAnimationFrame(now);
}
function run_tick() {
// This is where you handle things that don't happen "smoothly"
// (i.e., can't be calculated at a varying rate)
}
requestAnimationFrame(now);
setInterval(run_tick, 1000 / tick_rate);
对于某些事情,这绝对不是理想的方法,但在以已知时间间隔发生特定事件或计算更容易的情况下,它可以使事情变得更容易。
所以我有一台 120hz 显示器和一台 60hz 显示器。如果我 运行 我的游戏在第一个显示器上,它 运行 非常快,但是当我 运行 在第二个显示器上时,它会变慢。而且我知道那里也有很多 30hz 显示器,速度会更慢(还有一点点 240hz 显示器,速度快如闪电)。有什么方法可以将游戏的帧率锁定在 60fps(这是最常见的),这样问题就不会发生了?
不,requestAnimationFrame
应该在下一次屏幕刷新之前触发,这使其与屏幕刷新率相关联。
你需要的是 delta-time.
不是在每个滴答时按静态值增加对象位置,而是测量自上次滴答以来的时间,并根据经过的时间和预设持续时间更新您的值。
这样,无论显示器的刷新率如何,或者即使页面受到计算机等的限制,您的动画对象也会以相同的速度在任何地方行走给定的距离。
这里是一个例子,显示即使我们“暂停”动画,当我们“恢复”它时,对象也会在没有暂停的情况下应该在的位置。
const it = document.getElementById( "it" );
const checkbox = document.querySelector( "input" );
const maxLeft = window.innerWidth - 50;
const duration = 2000; // time to traverse the screen (ms)
const start = performance.now();
function anim( now ) {
// 'now' passed by rAF is the time the last VSync event has been sent by the monitor
// it may not be the real "now" time, for this one could use
// performance.now() instead
const delta = ((now - start) % duration) / duration;
// determine if we should go to left or to right
const direction = Math.sign( ((now - start) % (duration * 2)) - duration );
let position;
if( direction < 0 ) {
position = delta * maxLeft;
}
else {
position = maxLeft - (delta * maxLeft);
}
it.style.transform = `translateX(${ position }px)`;
if( checkbox.checked ) {
requestAnimationFrame( anim );
}
}
requestAnimationFrame( anim );
checkbox.oninput = anim;
#it {
width: 50px;
height: 50px;
background: red;
border-radius: 50%;
position: fixed;
top: 50px;
will-change: transform;
}
<div id="it"></div>
<label>pause/resume<input type="checkbox" checked></label>
Kaiido 的方法非常适合简单的动画和游戏,但如果您需要更复杂的功能,还可以采用其他一些方法。
假设某种操作每秒需要发生 n
次;我们称之为滴答声。一种方法是让 requestAnimationFrame
以及 setInterval
用于可能需要在帧之间发生的任务。例如:
var tick_rate = 50; // This is the ideal number of ticks per second
function draw_frame(now) {
// This code only handles the graphics
requestAnimationFrame(now);
}
function run_tick() {
// This is where you handle things that don't happen "smoothly"
// (i.e., can't be calculated at a varying rate)
}
requestAnimationFrame(now);
setInterval(run_tick, 1000 / tick_rate);
对于某些事情,这绝对不是理想的方法,但在以已知时间间隔发生特定事件或计算更容易的情况下,它可以使事情变得更容易。