soshimee
soshimee

Reputation: 438

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

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?

Upvotes: 2

Views: 386

Answers (2)

rydwolf
rydwolf

Reputation: 1528

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.

Upvotes: 1

Kaiido
Kaiido

Reputation: 136707

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>

Upvotes: 2

Related Questions