HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Efficient way to calculate game time

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
efficientwaytimegamecalculate

Problem

It's a common occurrence nowadays to have different refresh rates across different devices. That's why it's very important to keep track of the device's frame rate to keep the game time consistent across different refresh rates.

Is this an efficient way to go about this?

var timeBetween;
var timeLast;

function gameLoop() {
  var timeNow = window.performance.now();
  timeBetween = timeNow - timeLast;
  timeLast = timeNow;

  gameLogic(timeBetween); // Send time to game logic to calculate e.g. game speed etc.
  gameDraw();

  requestAnimationFrame(gameLoop);
}

Solution

One thing I recommend is to use a "scale factor" (I'm making names, there might be an official name for this approach) - a unit-less value that you multiply to time-sensitive values to compensate for frame rate differences. One perk when doing it this way is you don't have to write time sorcery in your equations (which is everywhere usually). You write them as is and just multiply this value to the result.

The formula is scale = delta / 16.6 where 16.6 is the frame time for 60fps. But this may differ per device, so you might need to find out the device refresh rate first and adjust this accordingly. According to MDN:


The number of callbacks is usually 60 times per second, but will generally match the display refresh rate in most web browsers as per W3C recommendation.
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

Here's an example calculation with a box that should move 60 units at 60fps. At 60fps, it moves an intended 60 units. But if the frame rate drops to 40fps, it should not move 40 units. Scale factor compensates for that by scaling up the calculated value.

// At 60fps, a frame takes 16.6ms
const delta = 16.6;
const scale = delta / 16.6; // 1
const boxMoved = 60; // your logic at 60fps calculates 60 units
const officialBoxMoved = boxMoved * scale; // 60

// At 40fps, a frame takes 25ms
const delta = 25;
const scale = delta / 16.6; // 1.5
const boxMoved = 40; // your logic at 40fps calculates 40 units
const officialBoxMoved = boxMoved * scale; // 60


Your code would look like:

let lastTime = performance.now();

(function gameLoop(currentTime){
  requestAnimationFrame(gameLoop);

  const scale = (currentTime - lastTime) / (100 / 6);
  lastTime = currentTime;

  gameLogic(scale);
  gameDraw();

}());


In terms of the code you just posted, there isn't much of a difference. But where the difference will be is in how you write your game logic using this value.

Code Snippets

// At 60fps, a frame takes 16.6ms
const delta = 16.6;
const scale = delta / 16.6; // 1
const boxMoved = 60; // your logic at 60fps calculates 60 units
const officialBoxMoved = boxMoved * scale; // 60

// At 40fps, a frame takes 25ms
const delta = 25;
const scale = delta / 16.6; // 1.5
const boxMoved = 40; // your logic at 40fps calculates 40 units
const officialBoxMoved = boxMoved * scale; // 60
let lastTime = performance.now();

(function gameLoop(currentTime){
  requestAnimationFrame(gameLoop);

  const scale = (currentTime - lastTime) / (100 / 6);
  lastTime = currentTime;

  gameLogic(scale);
  gameDraw();

}());

Context

StackExchange Code Review Q#160334, answer score: 2

Revisions (0)

No revisions yet.