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
    Mar 26 at 1:20

1 Answer 1

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

You must log in to answer this question.

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