Search Unity

Resolved How to generate unlimited nested children of objects randomly depth levels ?

Discussion in 'Scripting' started by Chocolade, May 18, 2022.

  1. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    The code now generate 100 objects at random positions.

    What i want to is to make something like this structure :

    Code (csharp):
    1.  
    2. Object 1
    3.      Child 1
    4.      Child 2
    5.          Child 3
    6.       Child 4
    7.  
    8. Object 2
    9.      Child 1
    10.      Child 2
    11.      Child 3
    12.  
    13. Object 3
    14.      Child 1
    15.          Child 2
    16.              Child 3
    17.  
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class GenerateObjects : MonoBehaviour
    7. {
    8.     public GameObject objectPrefab;
    9.  
    10.     [Range(1, 100)]
    11.     public int numberOfObjects = 1;
    12.  
    13.     private GameObject parent;
    14.     private int count = 0;
    15.  
    16.     // Start is called before the first frame update
    17.     void Start()
    18.     {
    19.         parent = GameObject.Find("Generate Objects");
    20.  
    21.         StartCoroutine(SpawnObjects());
    22.     }
    23.  
    24.     // Update is called once per frame
    25.     void Update()
    26.     {
    27.      
    28.     }
    29.  
    30.     IEnumerator SpawnObjects()
    31.     {
    32.         while (true)
    33.         {
    34.             yield return new WaitForSeconds(0);
    35.  
    36.             if (objectPrefab != null)
    37.             {
    38.                 GameObject go = Instantiate(objectPrefab, new Vector3(Random.Range(0,10), Random.Range(0,10), Random.Range(0,10)), Quaternion.identity,parent.transform);
    39.                 for(int i = 0; i < Random.Range(1,100); i++)
    40.                 {
    41.                     GameObject child = Instantiate(objectPrefab, new Vector3(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10)), Quaternion.identity, parent.transform);
    42.                     go.transform.SetParent(child.transform);
    43.                 }
    44.             }
    45.  
    46.             count++;
    47.  
    48.             if(count == 100)
    49.             {
    50.                 StopAllCoroutines();
    51.                 break;
    52.             }
    53.  
    54.             yield return null;
    55.         }
    56.     }
    57. }
    58.  
    The reason i'm using coroutine is to be able to control the spawning time.

    I tried to add this part for the children part but it's not working. it's randomly create children but only one depth level and not for all the objects the random is seems to be random parents that get a child.

    I want that each cloned prefab will have some children with unlimited random depths of levels.

    Code (csharp):
    1.  
    2. for(int i = 0; i < Random.Range(1,100); i++)
    3.                 {
    4.                     GameObject child = Instantiate(objectPrefab, new Vector3(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10)), Quaternion.identity, parent.transform);
    5.                     go.transform.SetParent(child.transform);
    6.                 }
    7.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    I think you just have this reversed ^ ^ ^ ^

    If you have this:

    Code (csharp):
    1. Object1
    2. Object2
    And you want this:

    Code (csharp):
    1. Object1
    2.     Object2
    Then the call would be:

    Code (csharp):
    1. Object2.transform.SetParent( Object1.transform);
    You are telling an object "This is your parent." Passing
    null
    to
    .SetParent()
    will unparent the object.

    Also if you want some other random spawning ideas, check out my MakeGeo project:

    MakeGeo is presently hosted at these locations:

    https://bitbucket.org/kurtdekker/makegeo

    https://github.com/kurtdekker/makegeo

    https://gitlab.com/kurtdekker/makegeo

    https://sourceforge.net/p/makegeo

    Particularly things with the word "spawn" in them.
     
    Chocolade likes this.
  3. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    I think i solved it. what do you think ? it's working.

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class GenerateObjects : MonoBehaviour
    7. {
    8.     public GameObject objectPrefab;
    9.  
    10.     [Range(1, 100)]
    11.     public int numberOfObjects = 1;
    12.     public int maxDepth;
    13.     public int currentDepth;
    14.  
    15.     private GameObject parent;
    16.     private int count = 0;
    17.  
    18.     // Start is called before the first frame update
    19.     void Start()
    20.     {
    21.         parent = GameObject.Find("Generate Objects");
    22.  
    23.         StartCoroutine(SpawnObjects());
    24.     }
    25.  
    26.     // Update is called once per frame
    27.     void Update()
    28.     {
    29.      
    30.     }
    31.  
    32.     IEnumerator SpawnObjects()
    33.     {
    34.         while (true)
    35.         {
    36.             yield return new WaitForSeconds(0);
    37.  
    38.             if (objectPrefab != null)
    39.             {
    40.                 GameObject go = Instantiate(objectPrefab, new Vector3(Random.Range(0,10), Random.Range(0,10), Random.Range(0,10)), Quaternion.identity,parent.transform);
    41.                 GenerateChildren(go);
    42.             }
    43.  
    44.             count++;
    45.  
    46.             if(count == 100)
    47.             {
    48.                 StopAllCoroutines();
    49.                 break;
    50.             }
    51.  
    52.             yield return null;
    53.         }
    54.     }
    55.  
    56.     GameObject child;
    57.     private void GenerateChildren(GameObject go)
    58.     {
    59.         if (currentDepth < maxDepth)
    60.         {
    61.             for (int i = 0; i < Random.Range(1,7); i++)
    62.             {
    63.                 child = Instantiate(objectPrefab, new Vector3(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10)), Quaternion.identity);
    64.                 child.transform.parent = go.transform;
    65.             }
    66.  
    67.             currentDepth++;
    68.             GenerateChildren(child);
    69.         }
    70.         else
    71.         {
    72.             currentDepth = 0;
    73.         }
    74.     }
    75. }
    76.  
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    Then ship it! Me studying the code isn't gonna change if it works or not. :)
     
    MelvMay likes this.
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,991
    I see the main issue has already be solved. However I'd like to point out that your original inner loop would have a really strange distribution since you roll a new random number each iteration.
    The distribution would be
    Code (CSharp):
    1. // i     p      total p
    2. // ...................
    3. // 0    1.00    1.0000
    4. // 1    0.99    0.9900
    5. // 2    0.98    0.9702
    6. // 3    0.97    0.9411
    7. // 4    0.96    0.9035
    8. // 5    0.95    0.8583
    9. // 6    0.94    0.8068
    10. // 7    0.93    0.7503
    11. // 8    0.92    0.6903
    12. // 9    0.91    0.6282
    13. //10    0.90    0.5653
    14. //11    0.89    0.5032 --> 50% chance
    15. //12    0.88    0.4428
    16. //13    0.87    0.3852
    17. //14    0.86    0.3313
    18. //15    0.85    0.2816
    19. //16    0.84    0.2365
    20. //17    0.83    0.1963
    21. //18    0.82    0.1610
    22. //19    0.81    0.1304
    23. //20    0.80    0.1043 --> 10% chance
    24. //21    0.79    0.0824
    25. //22    0.78    0.0643
    26. //23    0.77    0.0495
    27. //24    0.76    0.0376
    28. //25    0.75    0.0282
    29. //26    0.74    0.0209
    30. //27    0.73    0.0152
    31. //28    0.72    0.0110 --> 1% chance
    32. //29    0.71    0.0078
    33. //30    0.70    0.0055
    34. //31    0.69    0.0038
    35. //32    0.68    0.0026
    36. //33    0.67    0.0017
    37. //34    0.66    0.0011
    38. //35    0.65    0.0007
    39. //36    0.64    0.0005
    40. //37    0.63    0.0003
    41. //38    0.62    0.0002
    42. //39    0.61    0.0001
    43. // ...
    44. //50    0.50    10^-7
    45. // ...
    46. //60    0.40    10^-11
    47. // ...
    48. //70    0.30    10^-15
    49. // ...
    50. //80    0.20    10^-22
    51. // ...
    52. //90    0.10    10^-30
    53. // ...
    54. //99    0.01    10^-43
    55.  

    Not only is this quite inefficient to roll a new random number each iteration, what would be the intention behind it? with the limit of 100, the last elements will never be generated at all since the probability is lower than the probability that two GUIDs are equal.

    As for your new range (1 to 7) the probabilities are

    Code (CSharp):
    1. //0   1.0
    2. //1   0.8333
    3. //2   0.5556
    4. //3   0.2778
    5. //4   0.0926
    6. //5   0.0154
    7. //6   0.0
    8.  
     
    PraetorBlue and Kurt-Dekker like this.