有没有办法为非 60hz 的高/低帧率监视器设置 rAF 的 FPS?

问题描述

所以我有一台 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 次;我们称之为勾号。一种方法是为可能需要在帧之间发生的任务使用 requestAnimationFramesetInterval。例如:

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);

对于某些事情,这绝对不是理想的方法,但在某些情况下,在已知时间间隔内更容易发生特定事件或计算的情况下,它可以使事情变得更容易。