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

Question Great Confussion in accesing lists

Discussion in 'Scripting' started by Jinngineer, Nov 26, 2021.

  1. Jinngineer

    Jinngineer

    Joined:
    Apr 22, 2020
    Posts:
    41
    Hello,
    Im posting this after a week of working on this trying to figure out this problem.

    Google seems to have failed me :(

    I am a pretty noob person working on Unity and im still working on getting the syntax right.

    So the situation is following:
    -I am trying to Instantiate game objects;
    - The game objects are sometimes instantiating in the same position;
    -This is not a good thing, i want each instantiated object to be in its own unique position.
    - In order to do this i found an option using Physics, and though i think i got the syntax right, but it didnt work

    -My next attempt to fix the issue was to use a List to store the positions and then access it. I found a solution on the forums of stack overflow but when i attempted to implement it it wouldnt work.
    - I have searched Google and i failed to find a solution, so i turn to the mighty God of the Forum for assistance :)

    I will post both my attempts

    Attempt with List:

    Code (CSharp):
    1. void Walls()
    2.     {
    3.         List<GameObject> Children = new List<GameObject>();
    4.  
    5.         float totalPerc = (board.x * board.y * percernt) / 100;
    6.  
    7.         List<Vector3> childPos = new List<Vector3>();
    8.  
    9.         for (float j = 0; j< board.x; j++)
    10.         {
    11.            
    12.             for (float k = 0; k < board.y; k++)
    13.             {
    14.                            
    15.                
    16.                 if ( Children.Count < totalPerc)
    17.                 {
    18.                     float posX = Mathf.Round(Random.Range(0f, board.x - 1f));
    19.                     float posZ = Mathf.Round(Random.Range(0f, board.y - 1f));
    20.                     Vector3 pos = new Vector3(posX, 0.5f, posZ);
    21.  
    22.                     int indexX = 0;
    23.                     int indexZ = 0;
    24.  
    25.                     foreach(Vector3 Transform in childPos)
    26.                     {
    27.                         if (childPos[indexX].x != posX && childPos[indexZ].z == posZ)
    28.                         {
    29.                             GameObject wall = Instantiate(cube3, pos, Quaternion.identity);
    30.  
    31.                             wall.transform.SetParent(x.transform);
    32.                             Children.Add(wall);
    33.                             childPos.Add(wall.transform.position);
    34.                         }
    35.                         indexX++;
    36.                         indexZ++;
    37.                     }
    Attempt with Physics:

    Code (CSharp):
    1.  void Walls()
    2.     {
    3.         List<GameObject> Children = new List<GameObject>();
    4.  
    5.         for (float j = 0; j< board.x; j++)
    6.         {
    7.            
    8.             for (float k = 0; k < board.y; k++)
    9.             {
    10.                 float totalPerc = (board.x * board.y * percernt) / 100;              
    11.                
    12.                 if ( Children.Count < totalPerc)
    13.                 {
    14.                     float posX = Mathf.Round(Random.Range(0f, board.x - 1f));
    15.                     float posZ = Mathf.Round(Random.Range(0f, board.y - 1f));
    16.                     Vector3 pos = new Vector3(posX, 0.5f, posZ);
    17.  
    18.  
    19.  
    20.                     Vector3 overLapScale = new Vector3(1f, 0.5f, 1f);
    21.                     Collider[] collision = new Collider[1];
    22.                     int numbColliderOverlapped = Physics.OverlapBoxNonAlloc( pos, overLapScale, collision, Quaternion.identity, 0);
    23.  
    24.                     if ( numbColliderOverlapped==0 )
    25.                     {
    26.                         GameObject wall = Instantiate(cube3, pos, Quaternion.identity);
    27.  
    28.                         wall.transform.SetParent(x.transform);
    29.                         Children.Add(wall);
    30.                     }
    31.                    
    32.  
    33.                    
    34.  
    35.                    
    36.  
    37.                    
    38.                    
    39.                 }              
    40.             }
    41.         }
    42.     }
    43. }
    44.  
    I am not sure with which path to continue, they both do not seem to be working correctly :(

    Best Regards,
    Jinngeneer

    P.S. is there a place where syntax is simply explained? youtube tutorials usually explain how to do something but they dont always explain the logic behind it.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    I would go with the check-previous-positions approach.

    Alas, the limitations of a free tutorial!

    So my brief reading of your code in the first blurb is you are combining two different ways of deconflicting.

    On the one hand you are already iterating discrete X and Y positions on a board (line 9 and 12)

    On the other hand you are checking coordinates as well (line 25).

    I don't think you need ANY checking of coordinates as long as you are already considering every cell only once, which is what lines 9 and 12 do.

    APPROACH 1:

    So one method:

    - do lines 9 and 12 the way you are
    - use the coordinates based on j and k (do NOT choose randomly!)
    - choose a random chance of placing a guy there according to your desired density:

    Code (csharp):
    1. if (Random.value < ChanceOfEmplacement)
    2. {
    3.   // put guy here at cell (j,k)
    4. }
    This might have more or less than your goal children based on the random number gods.

    APPROACH 2:

    Another way is to:

    - choose a count in advance (the way some of your code does above)
    - make sure that count is LESS than the cell count (board cells)
    - loop over that count of children and for each one:
    --- choose a position
    --- loop over all already-emplaced children and if it collides, keep choosing random positions
    --- when you have found an open one:
    ----- emplace the object
    ----- add it to the list of already-emplaced children

    That's it. It will always have the precise count but it has more moving parts than the first approach.
     
  3. Jinngineer

    Jinngineer

    Joined:
    Apr 22, 2020
    Posts:
    41
    Hello Kurt,

    Thank you for the reply.

    I was looking at your 2nd approach... And maybe its my untrained eye, but that sounds like my approach using physics,

    -a count is chosen by line 10 (float totalPerc)

    - the count is less then the board amount.

    - positions are chosen at random line 14/15

    -i check the position for a collider line 20/21/22

    - if the collider is empty it should place an object there line 24

    In what way would you loop over all emplaced children?
    Im assuming youd use a List<Vector3> or List<Transform> and run that either through a series of if statements or a loop. But i cant find the syntax to pull up the coordinates of the positions in the list to check em.

    Best Regards
    Jinngineer
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Deconflicted spawning is such a fundamental property of so many games and it seems to come up here over and over again, so I created even more examples in my MakeGeo repository.

    This spawns in a grid:

    https://bitbucket.org/kurtdekker/ma...ocGenStuff/SpawningInAGrid/SpawningInAGrid.cs

    This spawns in an area / volume:

    https://bitbucket.org/kurtdekker/ma...tuff/SpawningOverAnArea/SpawningOverAnArea.cs

    Fully functional scenes are in the 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
     
  5. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,593
    So, I did some research on the topic, and I think one of the problems (the OverlapBox one) isn't working because the RigidBodies don't update their positions until the first Physics frame after they're Instantiated. You can update them manually using Physics.SyncTransforms, however I haven't tried it myself and don't know how performant it is.
     
    Bunny83 likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Agreed. The other consideration is, why involve Unity Physics and the entire train of dependency and tribal knowledge in something that is far simpler to solve by other means. (See links above).

    It DOES make sense to involve Unity and physics if you have a more complicated need such as irregularly-shaped and rotated pieces, but then you MUST understand it and use it perfectly. If you don't need that, don't muddy up your problem space with unnecessary API involvements.

    Remember: every API you involve requires that you use it perfectly, otherwise you just added another problem to your problem space, which will confound you solving the first issue.
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,895
    Suppose a work around for this could be to space out the instantiations by doing one per frame (or fixed update) in a coroutine?

    Naturally for loads of stuff this might be very noticeable should the player be looking at it.
     
    gamedev1506 likes this.
  8. Jinngineer

    Jinngineer

    Joined:
    Apr 22, 2020
    Posts:
    41
    Hello @Kurt-Dekker ,

    I wanted to thank you for your help :)

    I was able to get the code to work :D using your resources.

    Best Regards,
     
    Kurt-Dekker likes this.