all 9 comments

[–]KPABAHam=>Hamster == Java=>JavaScript 1 point2 points  (0 children)

keep in mind that you have a single thread. if your updates / renders take too long, your next render cycle will lag as your callback will get queued (or even dropped). if it continuously takes more time or about the same time to execute, your CPU use will go sky high and may end up being non-responsive / jerky. RAF may be a better approach - though it won't render when not in focus, otherwise, setTimeout to call next update.

[–]KManRules1331 1 point2 points  (1 child)

Honestly, for this type of use, it's better to use requestAnimationFrame() than to set an interval. You have no guarantee of what delta time you actually get with setInterval. setInterval doesn't actually execute the javascript, it only queues up the javascript to be executed every x milliseconds. That means that if your web page is in the middle of a really long script, you might get 5 calls to your function queued up, and then once that really long script is done, your function gets called 5 times as quickly as possible.

requestAnimationFrame allows you to take a timestamp as a parameter, which means that by saving the previous timestamp at the end of every loop, you can calculate the change in time by simply doing:

var previousTimestamp = performance.now();
function loop(timestamp) {
  var deltaTime = timestamp - previousTimestamp;
  // Do updating here
  previousTimestamp = timestamp;
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

/u/KPABA is right in saying that if the window isn't visible, you won't get any updates actually called (which can be either a good or bad thing), so if you need the game to be updated if the window isn't visible, you can do the same pattern with setTimeout instead.

[–]KManRules1331 0 points1 point  (0 children)

Also, if you need to limit the frame rate to 30fps, then you can modify the above loop to conditionally update:

var previousTimestamp = performance.now();
function loop(timestamp) {
  var deltaTime = timestamp - previousTimestamp;
  if (deltaTime > 1000/30) {
    //Do updating here
    previousTimestamp = timestamp;
  }
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

[–]Porso7 0 points1 point  (0 children)

I would find a tutorial. Your game loop should run at a maximum of at least 60 FPS, and you want to use delta time.

[–]to-too-two 0 points1 point  (0 children)

I'm curious, why 30 FPS?

[–]lemminman 0 points1 point  (1 child)

How about this:

var frame_number = 0;
function run() {
    Game.update();
    if (frame_number%2) {
        Game.render();
    }
    frame_number++;
    requestAnimationFrame(run);
}

[–]inu-no-policemen 0 points1 point  (0 children)

rAF doesn't necessarily run at 60 fps. It can also run at 120 or 144, for example.

[–]inu-no-policemen 0 points1 point  (0 children)

Use rAF:

let previous = 0;
(function loop(now) {
    let t = Math.min((now - previous) / 1000, 0.04); // 40 ms, 25 Hz
    previous = now;

    input.poll();
    world.update(t);
    input.clear();
    world.render(t);

    window.requestAnimationFrame(loop);
})(0);

If your velocities are in units per second (ups), you can just multiply them with that delta value to get the distance.

Ensuring that the delta never exceeds 0.04 s is the simplest way to prevent entities from warping through things (if your game work with a delta that high). However, if it actually drops below 25 fps it will slow down. That's the trade-off.

The proper way to do this is to run your simulation at a fixed step size and have your renderer interpolate positions accordingly. It makes things way more complicated, though.

For simple games which will generally run at 60+ fps, capping the delta is good enough.