问题
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