Looping a Script

I have the following script all set up and working, until it gets to the end and it tries to loop:

public bool isRaining;
public int minimumTimeUntilNextRainEvent;
public int maximumTimeUntilNextRainEvent;
public int timeUntilNextRainEvent;
public int minimumRainDuration;
public int maximumRainDuration;
public int RainDuration;
private bool countdownStarted;

//Sets the time until the next rainfall
public void StartRainEventCountdown()
{
    Debug.Log("Set time");
    timeUntilNextRainEvent = Random.Range(minimumTimeUntilNextRainEvent, maximumTimeUntilNextRainEvent);
    countdownStarted = true;
    StartCoroutine(Countdown());
}
//Starts the countdown until the next rainfall
private IEnumerator Countdown()
{
    Debug.Log("Countdown to rain");
    while (timeUntilNextRainEvent > 0)
    {
        timeUntilNextRainEvent -= 1;
        yield return new WaitForSeconds(5);
    }
    StartRain();
}
//Starts rainfall and choses duration
private void StartRain()
{
    Debug.Log("Started rain");
    isRaining = true;
    int RainDuration = Random.Range(minimumRainDuration, maximumRainDuration);
    StartCoroutine(Duration());
}
//Countdown until clear skies
private IEnumerator Duration()
{
    Debug.Log("counting til clear sky");
    while (RainDuration > 0)
    {
        RainDuration -= 1;
        yield return new WaitForSeconds(5);
    }
    StopRain();
}
//stops rainfall and resets the script
private void StopRain()
{
    Debug.Log("Stopped rain");
    isRaining = false;
    StartRainEventCountdown();
}

What exactly happens is it successfully runs through it once, but on the second run it only runs IEnumerator Countdown successfully before it runs the rest of the script on loop with no wait times. Basically it waits every time its told at first, waits through the first coroutine again, and then ceases to wait.

Hi @withlovegiftgiver ,

You redefine RainDuration in line 34 (StartRain()): int RainDuration = ...;. You thereby create a local variable, which is only valid within the StartRain() function scope.

I assume you set the global RainDuration in the inspector, it runs once and is then <0. You call StarRain() again, but as you redefine the variable, the global one does not get reset and is still <0. Ergo your rain immediately stops, as Duration() accesses the global variable.

Solution: Just drop the “int” :wink:

@Klarzahs is spot on. This is the main issue in your code. However you should avoid using such tangled coroutines anyways. Starting coroutines is expensive and produces garbage. It’s better to have a single coroutine and keep it running. Since you want an infinite cycle anyways your code can be simplified heavily

void Start()
{
    StartCoroutine(Rain());
}

IEnumerator Rain()
{
    var wait = new WaitForSeconds(5f);
    while (true)
    {
        int timeUntilNextRainEvent = Random.Range(minimumTimeUntilNextRainEvent, maximumTimeUntilNextRainEvent);
        while (timeUntilNextRainEvent > 0)
        {
            timeUntilNextRainEvent --;
            yield return wait;
        }
        isRaining = true;
        int RainDuration = Random.Range(minimumRainDuration, maximumRainDuration);
        while (RainDuration > 0)
        {
            RainDuration--;
            yield return wait;
        }
        isRaining = false;
        yield return null;
    }
}

Note the final yield return null; is a safety measure. In case your min and max values are smaller or equal to 0 none of your while loops would be entered. In this case you would never hit a yield statement and Unity would hang / freeze. Always makes sure you have a yield statement in your while loop.