0
\$\begingroup\$

So an object has a position, velocity, and is affected by gravity.

#include <simd/simd.h> // MacOS
struct Object {
    vector_float3 Translation; // Units
    vector_float3 Velocity; // Units per second
};

The game loop typically runs 60 times per second.

void ObjectUpdate(struct Object *obj) {
    obj->Velocity.y -= 9.80655/60;
    obj->Translation += obj->Velocity/60;
}

There are a couple problems with this approach:

  • Lag exists, so the assumption of 60 updates per second being embedded in the code is not great.
  • Floating point types are susceptible to precision errors at far distances from the origin, and are also more difficult to handle in some ways than integers.

I attempted to solve these with a fixed-point approach, and the use of clock() as well as keeping track of the time of the last update.

struct Object {
    vector_long3 Translation; // 65536ths of a unit
    vector_long3 Velocity; // 65536ths of a unit per second
    clock_t LastUpdate;
};
void UpdateObject(struct Object *obj) {
    const clock_t current = clock();
    const unsigned long delta = (unsigned long)((current-obj->LastUpdate)*(clock_t)65536/CLOCKS_PER_SEC); // Try to find the number of 65536ths of a second since the last update, in a way that it does not matter whether clock_t is integral or real
    obj->LastUpdate = current;
    obj->Velocity.y -= delta*642682>>16; // 642682 = 9.80655*65536
    obj->Translation -= delta*obj->Velocity>>16;
}

However, this suffers from other problems, most notably, being extremely chunky and unreliable. If I simply add delta to an accumulator and then print the accumulator, the value rises at an inconsistent rate, typically much slower than by 65536 per second.

How should I handle objects that need 'constant' updating and their updates are contingent on time?

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Safe to assume you've read Fix Your Timestep? A fixed timestep update is the usual solution to systems that need exact consistency. \$\endgroup\$
    – DMGregory
    Commented Mar 26, 2023 at 1:20

2 Answers 2

0
\$\begingroup\$

The problem was that clock() measures CPU time and not absolute time. Using clock_gettime() with CLOCK_MONOTONIC instead of clock() should solve the problem. The code will have to be updated to use struct timespec instead of clock_t like so:

struct Object {
    vector_long3 location; // 65536ths of a unit
    vector_long3 velocity; // 65536ths of a unit per second
    long last_update;
};
void Object_update(struct Object *obj) {
    struct timespec t;
    if (clock_gettime(CLOCK_MONOTONIC, &t))
        abort();
    const long current = t.tv_sec<<16|t.tv_nsec>>16, delta = current-obj->last_update;
    obj->last_update = current;
    obj->velocity.y -= delta*642682>>16; // 642682 = 9.80655*65536
    obj->location -= delta*obj->velocity>>16;
}
\$\endgroup\$
0
0
\$\begingroup\$

Edit: I see you solved this yourself. I will leave my comment in case someone fined the different perspectives useful. If you use the loop deltatime, and do not design based on absolute time, then there will be no problem. For example, in Unity, I use Time.deltatime in Update loops and never use Time.fixedDeltaTime in FixedUpdate loops.

Also, the idea of using an absolute time value, which increases throughout the application run, is not a good approach because the current time floating point value will suffer increased jitter just as spatial floating point values. To solve this, you can use current time = 0 always and count down to zero for all the timed events. For more information see Temporal floating origin

\$\endgroup\$

You must log in to answer this question.

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