Is there a way to set FPS for rAF for high/low frame rate monitors not on 60hz?

青春壹個敷衍的年華 提交于 2021-02-05 08:11:46

问题


So I have one 120hz monitor and one 60hz monitor. If I run my game on the first, it runs very fast, but when I run it at the second monitor, it's slower. And I know there are many 30hz monitors out there too, which would be even more painfully slow (and little bit of 240hz monitors, which would be lightning fast). Is there any way to lock the frame rate of the game to 60fps (which is the most common) so the problem doesn't happen?


回答1:


No, requestAnimationFrame is supposed to fire before the next screen-refresh, which makes it linked to the screen-refresh rate.

What you need is a delta-time.

Instead of incrementing your objects positions at every tick by a static value, measure how long it has been since the last tick and update your values based on that elapsed time and an pre-set duration.

This way, no matter the monitor's refresh rate, or even if the page gets throttled by the computer etc, your animated objects will walk a given distance at the same speed everywhere.

Here is an example showing that even if we "pause" the animation, when we "resume" it, the object will be at the place it should have been without the pause.

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>



回答2:


Kaiido's approach is great for simple animations and games, but there are a few other approaches you can take if you need more complex functionality.

Let's say some sort of operation needs to happen n times per second; we'll call this a tick. One approach would be to have the requestAnimationFrame, as well as a setInterval for tasks that need to occur potentially in between frames. For example:

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

This definitely isn't the ideal approach for some things, but in situations where it's much easier to have a certain event or calculation occur at a known interval it can make things easier.



来源:https://stackoverflow.com/questions/65623094/is-there-a-way-to-set-fps-for-raf-for-high-low-frame-rate-monitors-not-on-60hz

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!