#Issue with frame independent timer

1 messages · Page 1 of 1 (latest)

harsh basalt
#

Hello.
I'm having trouble in getting my dialogue system to print characters at a constant non-variable speed.

The code, in short, is supposed to print out characters (which are not spaces or part of a tag) at constant intervals.
I've tried a few other ways (including stopwatch, Time.time difference, throttling the state machine, different combinations of types, using floats instead of casting to int, capping the framerate, etc...) but nothing has worked.

When ran in the editor the speed at which the same line is printed varies around +-100ms on average.
In a build, the difference relative to each run is about 200ms on average, but all build runs are around 400ms faster than editor ones.

I would appreciate if anyone could point me in the right direction.

The code: https://pastebin.com/PgRrha6e

hallow thicket
#

(int)(Time.deltaTime * 1000) cuts out a lot of precision from deltaTime. If the game runs (for example) at steady 60 fps then deltaTime is 0.01666... and converting it to milliseconds it becomes 16 exactly, which cuts out 2/3 ms every frame. That accumulates to 40 ms discrepancy every second.

#

If you want it to be precise you have to add deltaTime as is without truncating it

harsh basalt
# hallow thicket `(int)(Time.deltaTime * 1000)` cuts out a lot of precision from deltaTime. If th...
{
    float charPrintDelay = 0.035f;
    string test = "AAAAAAAAA\0";

    float passedTime = 0f;

    int index = 0;

    Stopwatch stopwatch = new Stopwatch();

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        stopwatch.Start();
    }

    // Update is called once per frame
    void Update()
    {
        if (passedTime < charPrintDelay)
        {
            passedTime += Time.deltaTime;
            return;
        }

        char nextChar = test[index];

        if (nextChar == '\0')
        {
            if (stopwatch.IsRunning)
            {
                stopwatch.Stop();
                UnityEngine.Debug.Log($"Time taken: {stopwatch.ElapsedMilliseconds} ms");
            }

            return;
        }

        passedTime = 0f;

        UnityEngine.Debug.Log(nextChar);

        index++;
    }
}```

Even this, with no conversions or truncations has a varying completion time
hallow thicket
#

Use passedTime -= charPrintDelay instead of zeroing it

harsh basalt
#

Delay is about +-20 ms both ways

hallow thicket
#

Is that bad?

harsh basalt
#

in this case not so much because the string is short
But in the real system the error would add up quickly

#

Especially with pauses

hallow thicket
#

But does it? 20 ms is about 1 frame. You'll never get to exactly 0 difference because the stopwatch can only stop when Update runs each frame

harsh basalt
#

20 ms is 1 frame at less than 60 fps (which is 16. something if i'm not wrong)

#

In the example the game ran at about 300

hallow thicket
#

Well try it with a longer string and see what happens

harsh basalt
#

Variation increases with string length
This is at 117 characters

#

With capped frame rate

hallow thicket
#

After some tests, it's a combination of a measuring error and not incrementing the counter every frame so try this:

passedTime += Time.deltaTime;

if (passedTime < charPrintDelay)
{
    return;
}

and

if (nextChar == '\0')
{
    float expected = test.Length * charPrintDelay;
    UnityEngine.Debug.Log($"Time.time: {Time.time}, expected: {expected}, difference: {Mathf.Abs(Time.time - expected)}");
    return;
}
#

That gives me the same results regardless of string length

harsh basalt
#

This narrowed down the variation by a lot