Coroutine Countdown Timer being extremely slow

Hey guys so just as a disclaimer I’m relatively new to programming so if I’m making some super obvious mistake please go easy on me

So I’m trying to create a higher customizable Countdown timer for my game, and I want it to be able to be accurate to 0.01 Seconds. I decided I would use the Coroutine method for creating my timer instead of the delta-time one I have seen a couple of times, thinking that this would be a more efficient approach. My game is not very intensive and thus easily runs on hundreds of frames per second, so I thought that using Waitforseconds(0.01) is going to work better because it only needs to be called 100 times every second rather than multiple hundreds. however, I have come into a major issue with my timer. It is EXTREMELY slow. I ran the countdown timer on google and mine side by side starting at 25 seconds and it beat mine out by ten seconds. I even tried adding a artifical delay thinking the waitforseconds function was overshooting, so I would have the time tick down 0.01 seconds when a bit less then that had passed, but my results ended up being sort of inconsistent. Here is my code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TimerScript : MonoBehaviour
{
  public Text textDisplay;
  private double secondsLeft = 30;
  public bool takingAway = false;

   private string Texttodisplay;
   

   public int Milisecondsdigits = 2;
  void Start()
  {
      textDisplay = GetComponent<Text>();
      Texttodisplay = "00:" + secondsLeft;
      
      if(Milisecondsdigits == 0)
      {
          Milisecondsdigits = -1;
      }
  }

    void Update()
    {
        if (takingAway == false && secondsLeft > 0)
        {
            StopAllCoroutines();
            StartCoroutine(TimerTake());
        }
        
        if(Texttodisplay.Length > 8 - (Mathf.Abs(Milisecondsdigits -2)))
        {
            Texttodisplay = Texttodisplay.Substring(0,8- (Mathf.Abs(Milisecondsdigits -2)));
        }

        textDisplay.text = Texttodisplay;
    }

    IEnumerator TimerTake()
    {
        takingAway = true;
        yield return new WaitForSeconds(0.01f);
        secondsLeft -= 0.01;
        if(secondsLeft < 10)
        {
            Texttodisplay = "00:0" + secondsLeft;

        }
        

        else 
        {
             Texttodisplay = "00:" + secondsLeft;

        }

        takingAway = false;
    }

}

could somebody please let me know how I could cause this to become more accurate or why it’s acting extremely inaccurate currently :confused:

If you want to have higher accurate Timer I suggest using update as its much faster than doing in coroutine. Starting coroutines have a cost.


On top of that starting, a new instance of coroutine in every update is a bad approach. Pick one, Either use fully coroutine approach or all in Update() approach.


Additionally try to use stringValue.ToString( “FormatString” ) for formatting which is less garbage generating.


Read more about string and Garbage,


See below my approach for similar work,

public class CountDownTimer : MonoBehaviour
{
    [SerializeField]
    private Text _TextDisplay;

    public void StartCountDown( float seconds )
    { 
        StopCoroutine("IEnuCountDown");
        StartCoroutine(IEnuCountDown(_TextDisplay, seconds ));
    }

    IEnumerator IEnuCountDown( Text textBox, float countDown )
    {
        float timeLeft = countDown;

        while( timeLeft > 0f )
        {
            yield return new WaitForEndOfFrame();
            timeLeft -= Time.deltaTime;

            if( timeLeft < 0 )
            {
                timeLeft = 0;
                textBox.text = timeLeft.ToString( "00.##" );
                break;
            }
            else
            {
                textBox.text = "00.00";
            }
        }

        yield return 1;
    }

#if UNITY_EDITOR
    /// <summary>
    /// https://docs.unity3d.com/ScriptReference/ContextMenu.html
    /// </summary>
    [ContextMenu("Test Me")]
    public void TestMe()
    { 
        StartCountDown( 10f );
    }
#endif
}