- Home /
The question is answered, right answer was accepted
Coroutine making unity freeze
I know this is from the coroutine but I don't know how to fix it. Video showing the problem Here's my script:
#pragma strict
var RN : int = -1;
var groundPart : GameObject[];
var destroyCooldown : float = 5;
var redTime : float = 0.5;
var groundCount : int = 225;
function Start () {
groundPart = GameObject.FindGameObjectsWithTag("Ground");
groundCount = groundPart.Length;
StartCoroutine("DestroyGround");
}
function FixedUpdate () {
if(groundPart.Length <= 0 || groundCount <= 0){
StopCoroutine("DestroyGround");
}
}
function DestroyGround () {
while(true) {
RN = Random.Range(0, groundPart.length);
if(RN <= groundPart.length && groundPart[RN]) { groundPart[RN].GetComponent(MeshRenderer).material.color = Color.red;
yield WaitForSeconds(redTime);
groundPart[RN] = null;
//groundPart.Length -= 1; //might be the solution ?
yield WaitForSeconds(destroyCooldown);
RN = -1;
groundCount -= 1;
}
}
}
Thnaks for ur help.
Answer by Bunny83 · Sep 27, 2016 at 08:18 AM
A coroutine is a "cooperative" method. When you aren't cooperative inside of it it's your problem ^^. To be cooperative you have to make sure to call yield. First have a look at your method formatted in a way it makes sense:
function DestroyGround ()
{
while(true)
{
RN = Random.Range(0, groundPart.length);
if(RN <= groundPart.length && groundPart[RN])
{
groundPart[RN].GetComponent(MeshRenderer).material.color = Color.red;
yield WaitForSeconds(redTime);
groundPart[RN] = null;
//groundPart.Length -= 1; //might be the solution ?
yield WaitForSeconds(destroyCooldown);
RN = -1;
groundCount -= 1;
}
}
}
Here you can clearly see that all your yield statements are inside your "if" body. That means in the case where that if never turns true, your method essentially becomes:
function DestroyGround ()
{
while(true)
{
RN = Random.Range(0, groundPart.length);
}
}
As you can see when the if statement is not executed you are caught in an infinite loop without ever handing the control back to the system which results in a freeze.
So what are the possible reasons for the condition to become true. Your first condition is that RN is smaller or equal to "groundPart.length" (which btw makes no sense. It can't be equal, that would throw an out of bounds exception).
Since RN is Random.Range(0, groundPart.length);
it will always be in the range
0 <= RN < groundPart.length
So as long as your array is not empty the first condition doesn't give you any problems, even it's not necessary / useless.
The second condition is the important one: groundPart[RN]
You check if the element you're currently checking is not null. Since everytime you actually pick an element and you're entering the if statement you're setting the element to null. That means you eventually use up all elements in the array so all elements become null. In this case you will never enter the if statement ever again which will cause an infinite loop
thanks for ur answer I now understand how coroutine works, I can't acess to my computer right now but I'll keep u informed if it's now working (wich is propably the case). Thank you one more time.
It still don't working and I don't understand why... same bug... $$anonymous$$y new script is:
#pragma strict
var RN : int = -1;
var groundPart : GameObject[];
var destroyCooldown : float = 5;
var redTime : float = 0.5;
var groundCount : int = 225;
function Start () {
groundPart = GameObject.FindGameObjectsWithTag("Ground");
groundCount = groundPart.Length;
StartCoroutine("DestroyGround");
}
function FixedUpdate () {
if(groundPart.Length <= 0 || groundCount <= 0){
StopCoroutine("DestroyGround");
}
}
function DestroyGround () {
while(true) {
RN = Random.Range(0, groundPart.length);
if(groundPart[RN]) {
groundPart[RN].GetComponent($$anonymous$$eshRenderer).material.color = Color.red;
yield WaitForSeconds(redTime);
Destroy(groundPart[RN].gameObject);
//groundPart[RN] = null;
//groundPart.Length -= 1; //might be the solution ?
yield WaitForSeconds(destroyCooldown);
RN = -1;
groundCount -= 1;
}
break; //I also tried yield return new WaitForEndOfFrame(); and yield break; and yield return null and StopCoroutine("DestroyGround"); and all options :'(
}
}
so my question is how can I stop the coroutine once groundpart.lenght reach 0 ?
I found the solution: my unity editor was crashing so it did not registered I cahnged script so it didn't use the new one, IT's working now thank you so much !!!!!!!! I've been searching for the way to fix this for like 7 hour of search and thanks to the time you took to explain me I've found the solution ! Thank you again !!! +15 reputation point
Answer by iabulko · Sep 27, 2016 at 08:06 AM
If this
if(RN <= groundPart.length && groundPart[RN])
will return false then while(true) will loop to infinity in one frame, never letting it end. Add there something to let it go, or will break while loop, i.e.
while(true)
{
RN = Random.Range(0, groundPart.length);
if(RN <= groundPart.length && groundPart[RN]) {
...
}
yield return new WaitForEndOfFrame();
}
I did like u said and I get this error: UCE0001: ';' expected. Insert a semicolon at the end.
Follow this Question
Related Questions
Importing from Maya 2 Answers
New User, New Project 0 Answers
unity freezes repeatedly 1 Answer