1
\$\begingroup\$

I want this coroutine to execute continuously and change the colors. But right now it just waits 1 second at the start and then loops the Coroutine very fast.

So my question is how can I loop the Coroutine every 2 seconds.

public class control : MonoBehaviour
{
    public bool gravity = false;
    public bool m_isRunning = false;
    public SpriteRenderer m_spriteRenderer;
    private Rigidbody2D rb;

    private void Update()
    {
        if (gravity)
        {
            rb.gravityScale = 1;
        }

        StartCoroutine("Changecolor", 3f);
    }

    private void Start()
    {
        m_spriteRenderer = this.GetComponent<SpriteRenderer>();
        rb = GetComponent<Rigidbody2D>();
    }

    private IEnumerator Changecolor() <--- this coroutine
    {
        yield return new WaitForSeconds(1);

        int random = Random.Range(1, 4);
        if (random == 1)
        {
            m_spriteRenderer.color = Color.blue;
        }
        else if (random == 2)
        {
            m_spriteRenderer.color = Color.red;
        }
        else if (random == 3)
        {
            m_spriteRenderer.color = Color.green;
        }
        else
        {
            m_spriteRenderer.color = Color.yellow;
        }

        this.StartCoroutine("Changecolor", 3f);
    }

    private void OnMouseDown()
    {
        gravity = true;
    }
}
\$\endgroup\$
2
\$\begingroup\$

You're making the classic mistake of starting a new coroutine every frame in Update.

  • So in your first frame you start a coroutine, which waits one second.
  • Then in your next frame, you start another coroutine, which waits one second. Meanwhile the first has only 1 second minus 1 frame left to wait.
  • In your third frame, you start another coroutine...
  • ...
  • After one second, your first coroutine finishes waiting, and changes the colour, then itself starts another coroutine.
  • The very next frame, your second coroutine finishes waiting, changes the colour, and starts another coroutine...

So you change the colours every frame after the initial delay, and gradually fill up your memory and frame time with unwanted copies of the coroutine.

You can do all of this much simpler.

// Lookup table for colours.
static readonly Color32[] randomColors = new Color32[] {
    new Color32(0, 0, 255, 255),  // Blue
    new Color32(0, 255, 0, 255),  // Green
    new Color32(255, 0, 0, 255),  // Red
    new Color32(255, 255, 0, 0)   // Yellow
}

public bool gravity = false;
public bool m_isRunning = false;
public SpriteRenderer m_spriteRenderer;
private Rigidbody2D rb;   


void Start()
{
    m_spriteRenderer = this.GetComponent<SpriteRenderer>();
    rb = GetComponent<Rigidbody2D>();

    // Start the coroutine just once, in Start. Call it directly, not via a string.
    // You can pass your desired loop delay as an argument.
    StartCoroutine(ChangeColor(2f));
}

IEnumerator ChangeColor(float loopDelay) {
    // Loop this one coroutine instance forever.
    while(true) {
        // Select a new random colour from the array.
        int colorIndex = Random.Range(0, 4);
        m_spriteRenderer.color = randomColors[colorIndex];

        // Wait the specified duration before looping again. 
        // Move this to the top of the loop if you want a delay before changing colour the first time.
        yield return new WaitForSeconds(loopDelay);
    }
}

void Update() {
    if (gravity) {
        rb.gravityScale = 1;
    }

    // Do not start ever more copies of the coroutine here.
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy