Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

'brake' statement makes Unity hang ?

Discussion in 'Scripting' started by Alex_K98, Mar 25, 2015.

  1. Alex_K98

    Alex_K98

    Joined:
    Feb 12, 2015
    Posts:
    4
    Can someone explain why this code makes Unity hang?

    This code tries to find a non-intersecting position for objects generated.
    'prefab' is a common Unity sphere which size is set to (50,50,50).
    Default 'SphereCollider' is set to 'isTrigger' (just in case).

    I suspect 'break' call being the problem, because I have experienced strange behavior of 'return' call.

    Any help would be much appreciated.

    Important note: CalcPositions() works without problems in other engine!!!

    Here is the code:

    Code (CSharp):
    1. public GameObject prefab; //sphere of size (50,50,50)
    2. GameObject[] go; //array of these spheres
    3. int Count = 3; //size of array
    4. float minDistance = 50;
    5. float SceneRadius = 250; //area of position value generation
    6. Vector3 pos = new Vector3(0,0,0);
    7.  
    8. void Awake () {
    9.     go = new GameObject[Count];
    10.     Generate (); //generating objects
    11.     CalcPositions (); //calculating positions
    12. }
    13.  
    14. void Generate () {
    15.     for (int i = 0; i < Count; i++) {
    16.         Quaternion rot = Quaternion.identity;
    17.         go[i] = Instantiate (prefab, pos, rot) as GameObject;
    18.     }
    19. }
    20.  
    21. void CalcPositions () {
    22.     int j = 0;
    23.     for (int i = 0; i < Count; i++) {
    24.         Pos.x = Random.Range (-SceneRadius, SceneRadius);
    25.         Pos.y = 0; Pos.z = 0;
    26.         while (j < i) {
    27.             for (j = 0; j < i; j++) {
    28.                 Vector3 tempPos = go[j].transform.position;
    29.                 if (Vector3.Distance(tempPos, Pos) < minDistance) {
    30.                     break;
    31.                 }
    32.             }
    33.             Pos.x = Random.Range (-SceneRadius, SceneRadius);
    34.         }
    35.         go[i].transform.position = Pos;
    36.     }
    37. }
    38.  
    UPDATE: originally posted code lacked recalculation of position inside a 'while' loop. So, I updated it, but infinite loop problem still happens.
    UPDATE 2: renamed 'ObjectRadius' to 'minDistance' for the sake of simplicity.
     
    Last edited: Mar 26, 2015
  2. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422

    Yes the break statement is causing this issue.

    Note, that call to break will break out of the for loop and drop back into the while loop, which will then drop into the for loop again, until break is hit which will again break out to the while loop, repeat for eternity.

    I've got no idea what you're tying to do there, but the while loop looks superfluous, perhaps remove it (?)
     
  3. Alex_K98

    Alex_K98

    Joined:
    Feb 12, 2015
    Posts:
    4
    You are right, I forgot to recalc new position inside a 'while'. But infinite loop problem still happens.
    The idea is to find a non-intersecting position for all the objects. I agree that this is probably should/can be done some other way, but it was the first idea... Should you have any suggestions, it would be much appreciated. Thanks.
     
  4. TheValar

    TheValar

    Joined:
    Nov 12, 2012
    Posts:
    760
    When you call break you are breaking out of the inner most forloop but remaining in the while loop. You are most likely seeing infinite loops because break is being called while j<i. Since your while loop will never modify j it will always remain less than i and the loop cannot complete.
     
  5. TheValar

    TheValar

    Joined:
    Nov 12, 2012
    Posts:
    760
    Looking more at your code there are a few more problem you have to deal with besides the infinite loop.

    If I'm understanding your logic correctly you are trying to set a random position, check all previous positions and try a new random position if there is an intersection. Right now a new random position will be set whether there is a collision or not.

    Additionally when checking a collision you should see if the distance between them is less than ObjectRadius * 2(diameter).
     
  6. Zaladur

    Zaladur

    Joined:
    Oct 20, 2012
    Posts:
    392
    Yea toss the while loop completely. if you ever break the inner for loop, you will never escape the while loop, and if you ever complete the for loop, you will never loop on the while condition. It does nothing for you but cause infinite loops.
     
    Kiwasi and TheValar like this.
  7. Alex_K98

    Alex_K98

    Joined:
    Feb 12, 2015
    Posts:
    4
    I'll check this, thanks.

    Sure. Actually, this is my mistake in calling variable ObjectRadius. For the sake of simplicity it should be considered a 'minDistance'. I'll update the code to correct this moment.
     
  8. Alex_K98

    Alex_K98

    Joined:
    Feb 12, 2015
    Posts:
    4
    I've updated the code slightly, to make sure it never falls into infinite loop, but the drawback is that there will be position generation errors. I'll will still have to check what TheValar proposed in a message above regarding original code.

    Code (CSharp):
    1.  
    2. public GameObject prefab; //sphere size is (50,50,50) - it is diameter, not radius
    3.  
    4. GameObject[] go; //array of these spheres
    5. int Count = 3; //size of array
    6.  
    7. float minDist = 50;
    8. float SceneRadius = 250; //area of position generation
    9.  
    10. int safetyCounter = 0;
    11. int safetyCounterLimit = 24;
    12.  
    13. int j = 0; int i = 0;
    14. Vector3 pos = Random.inUnitSphere * SceneRadius; //just so it is not zero
    15.  
    16. void Awake () {
    17.     go = new GameObject[Count];
    18.     Generate (); //generating objects
    19.     CalcPositions (); //calculating positions
    20. }
    21. void Generate () {
    22.     for (i = 0; i < Count; i++) {
    23.         Quaternion Rot = Quaternion.identity;
    24.         go[i] = Instantiate (prefab, Pos, Rot) as GameObject;
    25.     }
    26. }
    27. void CalcPositions () {
    28.    //making sure the first object in array has non (0,0,0) position
    29.    go[0].transform.position = Pos;
    30.  
    31.    for (i = 0; i < Count; i++) {
    32.      while (j < i) {
    33.        Pos = Random.inUnitSphere * SceneRadius;
    34.        if (Pos.magnitude < SceneRadius) {
    35.          for (j = 0; j < i; j++) {
    36.            if (Vector3.Distance(go[j].transform.position, Pos) < minDist) {
    37.              safetyCounter++;
    38.              break;
    39.            }
    40.          }
    41.        }
    42.        if (safetyCounter > safetyCounterLimit) {
    43.          go[i].name = "Oops, increase SceneRadius!";
    44.          go[i].SetActive(false);
    45.          break;
    46.        }
    47.      }
    48.      go[i].transform.position = Pos;
    49.    }
    50. }