Coroutine takes different amount of time between scenes

Just a bit confused as to why this is happening: I have a coroutine that does a simple animation where it takes a starting number and an ending number and shifts the starting number to the ending number in a text object. I have this script on its own object specifically for this purpose and that object is a prefab that remains unchanged between scenes. It works perfectly fine when in the scene I designed it in as well as an additional scene, but I just recently put it in a different scene without changing anything and it runs very slow comparatively. Something like 2-3 times as slow. Does anyone know why this is happening and how to fix it?

Here is the coroutine:

IEnumerator transitionValue(int startAmount, int endAmount) 
{
    int difference = 0;
    int trackVal = startAmount;
    int changeAmount = 1;
    ended = false;
    currencyText.text = $"{startAmount:n0}";
    if (startAmount > endAmount) 
    {
        downOrUp = true;
        difference = startAmount - endAmount;
    } 
    else if (startAmount < endAmount) 
    {
        downOrUp = false;
        difference = endAmount - startAmount;
    }

    float timeBetweenRuns = 0.1f/difference;
    if (difference > 500)
    {
        changeAmount = 2;
    }
    else if (difference > 1000)
    {
        changeAmount = 3;
    }
    else if (difference > 3000)
    {
        changeAmount = 4;
    }
    else if (difference > 10000)
    {
        changeAmount = 5;
    }
    else if (difference > 20000)
    {
        changeAmount = 10;
    }

    while (!ended) 
    {
        if (trackVal == endAmount)
        {
            ended = true;
            break;
        }
        if (downOrUp)
        {
            trackVal -= changeAmount;
        }
        else 
        {
            trackVal += changeAmount;
        }
        currencyText.text = $"{trackVal:n0}";
        yield return new WaitForSeconds(timeBetweenRuns);
    }
    if (!downOrUp)
    {
        foreach (string[] stat in data.stats)
        {
            if (stat[0] == data.currentUser && stat[1] == "Bonepoints")
            {
                stat[2] = "" + endAmount;
            }
        }
    }
    currentBonePoints = endAmount;
}

I’m assuming timeBetweenRuns is usually a very tiny amount of time? If this is the case, it will be mostly ignored because coroutines, just like everything else in a game engine, are ultimately limited by the frame rate. So if you’re running 60FPS for example, you can set timeBetweenRuns to be as small as you want, but it will still take 1/60 of a second for the next iteration of the coroutine to run.

You typically fix issues like this by using Time.deltaTime. Instead of adding set numbers on each iteration, like changeAmount in your case, you add Time.deltaTime. This property gives you the amount of time passed since last frame, so no matter how low or high your FPS currently is, time measurements will stay consistent throughout the coroutine. And then you can just use yield return null instead of WaitForSeconds. yield return null will just continue on the next frame.

2 Likes

I mean your calculation of float timeBetweenRuns = 0.1f/difference will lead to some wildly different times. It may not be due to the scene but simply the difference in values you’re supplying.

This is honestly a lot of code for what could be boiled down to something like Mathf.MoveTowards, and simply updating the text component at a fixed interval.

My calculation of the timeBetweenRuns is intentional and yes it will lead to wildly different times, by design. Its essentially just a lazy programmers way of making this “animation” take the same amount of time regardless of how many values are being spanned. Mathf.MoveTowards wouldn’t work because of how I need to interact with my data storing system and with how much I want to eventually control the speed.

If I do this, how do I control the speed at which the animation runs?

Nevermind I figured it out, thanks!

How you manipulate the presentation of the data, and the underlying data itself, are two separate things. So, you should be updating the underlying data immediately, but the visuals of said data can update at its own schedule.

Upon thinking, Math.Lerp is probably better, as you can run a loop for x amount of time, lerping the number from a start to finish value based on your time interpolation.

  1. not how the my data system works
  2. Math.Lerp would save maybe like 10 lines of code, so I dont care
  3. I said would make the animation take roughly the same amount of time, which it does visually. Your comment about the 0.2 vs 5 doesn’t make sense, the higher value change needs higher change amount to take the same amount of time as the first.