Javascript - Can't Adjust FrameRate - requestanimationframe

11,231

Solution 1

A bit late to the party, but here's how to get the benefit of RAF while also controlling frames/second.

Note: requestAnimationFrame now has a better way of doing things than by using the code pattern in my original 3 year old original answer ... see my update below for the new and improved way.

[Update: requestAnimationFrame now has a better way of throttling]

The new version of requestAnimationFrame now automatically sends in a current timestamp that you can use to throttle your code execution.

Here is example code to execute your code every 1000ms:

var nextTime=0;
var delay=1000;

function gameLoop(currentTime){
    if(currentTime<nextTime){requestAnimationFrame(gameLoop); return;}
    nextTime=currentTime+delay;
    // do stuff every 1000ms
    requestAnimationFrame(looper);
}

}

Solution 2

You should look at this article which gives a proper treatment of the subject. http://creativejs.com/resources/requestanimationframe/

var fps = 15;
function draw() {
    setTimeout(function() {
        requestAnimFrame(draw);
        // Drawing code goes here
    }, 1000 / fps);
}

Here is the code I think you want, but in the original article it said used requestAnimationFrame, but here I am using requestAnimFrame. I think maybe it changed and you're supposed to use requestAnimFrame now. requestAnimationFrame did not work for me while requestAnimFrame did.

Solution 3

The way browsers and javascript work makes it difficult to set up a fixed frame rate. Say you want to do something every one second, like updating and drawing. One way of doing that could be to call window.setTimeout() with a setting of one second. But the problem is that this is not that reliable, even if you configure a callback every second you can't be sure all callbacks will be in time. A high processor load, for example, could make the callbacks arrive much later than they should. And even if the callbacks would be on time, you have no control of when the actual drawing to the screen will happen.

A better way of handling it is to accept the fact that you can't get a very precise timing of your calls, and instead, whenever you get a call, you calculate how much time has passed and act according to that. This means you'll let the system decide the frame rate, and you just take care of updating your animation or game depending on how much time that has passed.

requestAnimationFrame is a newer functionality supported by most browsers by now that is especially useful for games. It will be called every time the browser is ready to draw, which is good. Then you will know that the updates and drawing you are doing will happen right before the actual frame is drawn to screen.

Here's an example on how you could update your gameLoop to take the time difference into account.

var lastTimestamp = +new Date;

function gameLoop(timestamp) {
  var now = +new Date;
  var dt = now - lastTimestamp;

  // dt is the amount of time in ms that has passed since last call.
  // update takes this time difference (in seconds) and can then perform its
  // updates based on time passed.
  update(dt / 1000);
  draw();
  lastTimestamp = now;
  requestAnimationFrame(gameLoop);
}
Share:
11,231
Lumo5
Author by

Lumo5

Updated on July 24, 2022

Comments

  • Lumo5
    Lumo5 almost 2 years

    I start the loop

    function gameLoop(){
       update();
       draw();
       requestAnimFrame(gameLoop);
    }
    
    var requestAnimFrame =  window.requestAnimationFrame ||
                        window.webkitRequestAnimationFrame ||
                        window.mozRequestAnimationFrame ||
                        window.oRequestAnimationFrame ||
                        window.msRequestAnimationFrame ||
                        function(callback) {
                            window.setTimeout(callback, 1000 / 1);
                        };
    
    1. I can't adjust the frame rate. It is always really fast. Why can't I change it to 1 frame a second. I want to do this just for testing purposes.
    2. Do I have to clear the canvas each time? It seems to work good without clearing it.

    Thanks.

    Here is a link to a fiddle for the complete code: complete code

    Thanks

  • nerkn
    nerkn over 9 years
    Sounds very logical and clever.
  • Daniel Alder
    Daniel Alder almost 8 years
    shouldn't you swap setTimeout and requestAnimationFrame somehow? In your example, update and draw are called at the setTimeout event, still async while the gameloop() body is in sync (but does nothing than setting the timeout)
  • markE
    markE almost 8 years
    @DanielAlder. This code is a couple years old and now requestAnimationFrame automatically sends in a timestamp so the setTimeout is no longer required. Use the timestamp to throttle the animation.
  • Daniel Alder
    Daniel Alder almost 8 years
    Sure but your code is wrong anyway. It was in 2013 and it is now.
  • markE
    markE almost 8 years
    @DanielAlder Well, this code is not "wrong" and it does indeed work...it's just been superceded by better capabilities. I've updated my answer to reflect the new capabilities :-)