2
\$\begingroup\$

this is what i did

my game loop is run every REFRESH milliseconds

loop = setInterval(tick,REFRESH);

in the loop i calculate how much time is passed since last tick and subdivide that for how much time i expected to be passed

var now = performance.now();
var elapsedTime = now - lastTick;
var delta = time / REFRESH;
lastTick = now;

and every time based action that should happen every tick is "scaled" with the delta factor, for example my movement code

var distance=ball.dest.x-ball.x;
var movement=distance/speed;
ball.x+=movement;

will have movement multiplied with delta

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Your approach is unfortunately not framerate independent. You correctly notice the need to factor in the amount of time passed between each update in your physics calculations. However, you still specify the amount of time passed in units of frames. If your framerate changes, now your speeds have all changed with respect to the passing of real time. What you should do instead is pass the actual time passed between each frame in units of seconds or ms or us or whatever.

In your first example, the change is simply passing elapsedTime rather than delta. In the second half you need to calculate the speeds of items with respect to the passing of real time, like pixels/second or meters/second rather than pixels/frame.

\$\endgroup\$
1
\$\begingroup\$

Don't use setInterval for game loops. Use requestAnimationFrame. See the simple example below.

console.clear();
const INTERVAL = 16; //16 ms animation interval
var frame = {
  start: null,
  delta: null,
  count: 0,
};

run(test);

function run(func) {
  if (!frame.start) frame.start = performance.now();
  frame.delta = performance.now() - frame.start;
  if (frame.delta >= INTERVAL) {
    func.call();
    frame.start = null; //reset
    frame.count++;
  }
  //for this example the loop will be repeated only 100 time
  if (frame.count < 100) requestAnimationFrame(run.bind(null, func));
  //without counting limit
  //requestAnimationFrame(run.bind(null, func));
}

function test() {
  //simple function for demonstration
  // avoid using console in animation loop, except for debugging
  // console operations are very slow
  console.log(`${frame.count}`);
}

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Quite often games will use a while( remainingDelta > interval) loop rather than a single if, to run a fixed update function at a rate decoupled from the visual update tick — sometimes multiple calls per visual update. For this, it's good not to null-out the start each time, but to keep track of how much "loose change" is leftover after calling the fixed update, so we can carry it forward to the next loop & avoid "lost time" \$\endgroup\$
    – DMGregory
    Commented Mar 22, 2019 at 11:58
  • \$\begingroup\$ @DMGregory, thanks. This is something I have yet to learn. \$\endgroup\$
    – Lovro
    Commented Mar 22, 2019 at 12:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .