Thread overview
Delta Time - Streamlined Time Keeping For Games
Aug 20, 2022
jordan4ibanez
Aug 20, 2022
Abdulhaq
Aug 20, 2022
jordan4ibanez
Aug 20, 2022
jordan4ibanez
Aug 21, 2022
Abdulhaq
Aug 21, 2022
jordan4ibanez
Sep 03, 2022
cc
Aug 21, 2022
Zoadian
Aug 21, 2022
jordan4ibanez
Aug 21, 2022
jordan4ibanez
August 20, 2022

This library is extremely simple. A time keeping library for game development.

You can see/get it here: https://code.dlang.org/packages/delta_time

Many things in games are bound to a simple constraint: time. In years past, games would commonly link the game's logic to the FPS, but if FPS goes too high, or too low. All of a sudden the player's experience is greatly skewed. So a very simple fix for this was to get a calculation of the time between the last frame and the current frame, then multiply all logic by this value.

This library allows you to track it precisely between frames. Nanoseconds precise.

Here's a bare bones example on how to use it:

import delta_time;

void main() {
   bool gameRunning = true;
   // The root loop of the entire game
   while(gameRunning) {
      calculateDelta();

     // Now anywhere in the program on the main thread
     // if delta_time is imported, it can access it by running this:
     double theDelta = getDelta();
   }
}

The first delta will always be 0, as there is no before time to calculate. Hopefully this helps you with your game. Thanks for reading.

August 20, 2022

On Saturday, 20 August 2022 at 00:32:25 UTC, jordan4ibanez wrote:

>

This library allows you to track it precisely between frames. Nanoseconds precise.

just out of curiosity, when you say nanoseconds precise do you mean to imply it is nanoseconds accurate? And if so, what makes you confident that that is the case?

August 20, 2022

On Saturday, 20 August 2022 at 11:26:08 UTC, Abdulhaq wrote:

>

On Saturday, 20 August 2022 at 00:32:25 UTC, jordan4ibanez wrote:

>

This library allows you to track it precisely between frames. Nanoseconds precise.

just out of curiosity, when you say nanoseconds precise do you mean to imply it is nanoseconds accurate? And if so, what makes you confident that that is the case?

Because it is using the built in MonoTime. Which represents time in system clock ticks utilizing the highest precision your system allows. I should have clarified this gives you a USABLE delta, not an integer or long. A double where you can just plop it into code that's frame locked and get code that now basically interpolates between frames properly. This is what I mean by "keeping time". Not adding a bunch of values together to get the total delta value since the program started, or trying to get the beginning of the universe, just a value that allows player's to have an enjoyably consistent experience.

So here is the actual calculation:

Duration duration = after - before;
delta = cast(double)duration.total!("nsecs") / 1_000_000_000.0;

So I would understand if you have a response of: "WAIT, THAT'S A DOUBLE! THAT'S NOT PRECISE!". And you're absolutely right, but if you do this calculation yourself to get delta time, you will still get the same double floating point errors. But the base calculation using MonoTime is absolutely precise. (Precise in the library code. Now in the field, well the follow up is some examples)

If this is incorrect when calculated in your system there are five possibilities:

  1. The library is wrongly implemented for your operating system, open a bug report into the library.
  2. A stray particle of radiation has hit the floating point calculation in your cpu. I can't help with this. Shield with lead.
  3. You have managed to perfectly time your FPS to the point where the timestamp division to get the real time in a usable format in seconds has managed to find it's way into the precision loss of IEEE-754. (I'm happy for you for having such a powerful pc) In this case, we need 128bit floating point calculators in computers. But I do not manufacture cpus.
  4. Your cpu is so old that the timestamp total! throws an error or returns 0 for the "nsecs" call. There's really nothing I can do about that one.
  5. You have overclocked your system and done something horribly, horribly wrong to the point where it affects the system's ability to keep time at all.

There are probably many, many, many more situations where things just go absolutely insane. But at that point, I cannot possibly go out to a location and diagnose operating system and hardware things for everyone because that's expensive and I am just one person. I hope this clarifies things. Thank you for reading.

August 20, 2022

On Saturday, 20 August 2022 at 11:26:08 UTC, Abdulhaq wrote:

>

On Saturday, 20 August 2022 at 00:32:25 UTC, jordan4ibanez wrote:

>

This library allows you to track it precisely between frames. Nanoseconds precise.

just out of curiosity, when you say nanoseconds precise do you mean to imply it is nanoseconds accurate? And if so, what makes you confident that that is the case?

So basically, what I am saying is, you WILL get the same double floating point number no matter what way you try to do this if the situation on the player's computers are identical. And yes I am saying it is nanoseconds accurate, the base implementation is for the duration. When it is given into a usable value. Well, I think you know what the following will print :P

import std.stdio;
double a = 0;
// Do some math with a
double b = 0;
// Do some other math with b that should yield the EXACT value of a
writeln("Does a == b? ", a == b);

You could (technically) use the delta time to keep the total time that the program has been running. But the time skew due to double floating point precision might end up leaving your program thinking it's been on for a few days if you left it on for a week or two. I'm kidding, but you will end up with a time skew of perhaps a few seconds or minutes depending on how badly your cpu calculates MonoTime Duration, along with how many errors the double floating point calculation encounters.

So basically what I'm saying is: It is absolutely accurate down to the nanosecond, in code, in the base calculation of Duration. But the conversion from this calculation to usable double floating point values in production for player experience will always be inaccurate. This is why you do not do any financial calculations in float or double haha. I hope this clarified everything. Thank you for reading.

August 21, 2022

On Saturday, 20 August 2022 at 00:32:25 UTC, jordan4ibanez wrote:

>

This library is extremely simple. A time keeping library for game development.

[...]

I just want to throw this link here because it explains the 'correct' way to do game loops: https://gafferongames.com/post/fix_your_timestep/

August 21, 2022

On Saturday, 20 August 2022 at 22:29:13 UTC, jordan4ibanez wrote:
Thanks for your detailed reply Jordan :-). I think I need to explain my question in more detail.

The first generation atomic clock was acccurate to 10e-11 seconds or 1/100 nanosecond https://en.wikipedia.org/wiki/Atomic_clock#Accuracy.

PC clocks in general (assuming you are talking about PCs here) seem to be heading towards an accuracy of near 10 nanoseconds (https://stackoverflow.com/questions/2607263/how-precise-is-the-internal-clock-of-a-modern-pc).

So I suspect that although from you lower level calls you may be receiving readings as doubles, in fact the actual accuracy (and I mean accuracy, not precision https://manoa.hawaii.edu/exploringourfluidearth/physical/world-ocean/map-distortion/practices-science-precision-vs-accuracy) is probably not 1 nanosecond. However, maybe you're doing something that I'm not expecting or I don't know about (very possible), hence the question.

August 21, 2022

On Sunday, 21 August 2022 at 11:37:35 UTC, Zoadian wrote:

>

On Saturday, 20 August 2022 at 00:32:25 UTC, jordan4ibanez wrote:

>

This library is extremely simple. A time keeping library for game development.

[...]

I just want to throw this link here because it explains the 'correct' way to do game loops: https://gafferongames.com/post/fix_your_timestep/

I'm just going to put in a min/max allowed delta for you to set at the beginning of the program's execution. I've been there done that with the accumulator. On low end machines you will end up with a cycles loop unless cycles are limited in the accumulator that will end up freezing the program. Even with this, you will end up with a slow down as if you just ended up doing the min/max limiter regardless. Excessive environmental variables make both of these terrible solutions if you want unlimited accuracy, which is not possible currently with real time games. I do appreciate you showing me this regardless because I can warn other developers in advance

August 21, 2022

On Sunday, 21 August 2022 at 12:02:20 UTC, Abdulhaq wrote:

>

On Saturday, 20 August 2022 at 22:29:13 UTC, jordan4ibanez wrote:
Thanks for your detailed reply Jordan :-). I think I need to explain my question in more detail.

The first generation atomic clock was acccurate to 10e-11 seconds or 1/100 nanosecond https://en.wikipedia.org/wiki/Atomic_clock#Accuracy.

PC clocks in general (assuming you are talking about PCs here) seem to be heading towards an accuracy of near 10 nanoseconds (https://stackoverflow.com/questions/2607263/how-precise-is-the-internal-clock-of-a-modern-pc).

So I suspect that although from you lower level calls you may be receiving readings as doubles, in fact the actual accuracy (and I mean accuracy, not precision https://manoa.hawaii.edu/exploringourfluidearth/physical/world-ocean/map-distortion/practices-science-precision-vs-accuracy) is probably not 1 nanosecond. However, maybe you're doing something that I'm not expecting or I don't know about (very possible), hence the question.

Ohh I get it. No I'm not doing anything that advance with atomic clocks. I cannot change forum posts so let's just leave it at: "I tried to make this as accurate as possible for your machine down to the nanosecond" :P

August 21, 2022

I have taken in the notes here and allowed devs to have more control over the delta max so that the game can slow down and get more accurate calculations if everything is going horribly wrong:

// Allows devs to set the max delta time before the game starts to slow down
void setMaxDelta(double newDeltaMax) {
    maxDelta = newDeltaMax;
}

// Allows devs to set the specific FPS where the game will start to slow down if it drops below
void setMaxDeltaFPS(double FPS) {
    maxDelta = 1.0 / FPS;
}

By default: it's 0.2 in real terms or 5 FPS in game terms. Any lower FPS/higher delta than that and the game logic will slow down

September 03, 2022

On Sunday, 21 August 2022 at 22:54:57 UTC, jordan4ibanez wrote:

>

Ohh I get it. No I'm not doing anything that advance with atomic clocks. I cannot change forum posts so let's just leave it at: "I tried to make this as accurate as possible for your machine down to the nanosecond" :P

MonoTime is not necessarily returning a value with nanosecond accuracy, however. On Windows, QueryPerformanceCounter is used (by default, other implementations may be available), which in this case returns values in Ticks of hecto-nanoseconds, so calls to duration.total!("nsecs") are going to return a multiple of 100.

MonoTime reports its internal values through .ticks and .ticksPerSecond, so I like to use those. Ultimately the end result comes out to the same, but it avoids additional conversions and a magic number in the code, and maybe provides a little future proofing against potential exotic architectures.

writefln("%,d", MonoTime.ticksPerSecond); // 10,000,000
double doubleTicksPerSecond = cast(double) MonoTime.ticksPerSecond;
long lastTicks = MonoTime.currTime.ticks;
...
// loop
	long nowTicks = MonoTime.currTime.ticks;
	delta = cast(double)(nowTicks - lastTicks) / doubleTicksPerSecond;
	lastTicks = nowTicks;

https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency
https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter