- Home /
The question is answered, right answer was accepted
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.
Answer by Bunny83 · Oct 24, 2020 at 01:10 AM
@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.
Of course if you want / need you can make the two counter variable member variables as you have it in your original script. Though if you don't really need them it's usually better to keep them encapsulated. It reduces unwanted errors.
Answer by Klarzahs · Oct 23, 2020 at 11:59 PM
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" ;)
Follow this Question
Related Questions
How does WaitForSeconds pass values? 0 Answers
Why isn't my simple coroutine working? (and how can I make it infinite?) 2 Answers
Problem with coroutine 2 Answers
How to change a large number of booleans as fast as possible without sacrificing framerate? 1 Answer
Rerun a script after it finishes, when it already has multiple Coroutines? 1 Answer