Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

2D game spawn overlapping

Discussion in 'Scripting' started by imposter_syndrom_incarnated, Sep 22, 2020.

  1. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    Hello,

    apologies in advance if it's a question that has been asked before by others. I have tried to implement the suggested methods but it still did not work. I am trying to make sure there is no overlap when the cards are spawned.

    The scene produces some cards, 10 here in the picture below, one by one, in random positions. When the button is clicked, it produces new cards again.

    upload_2020-9-22_12-34-20.png

    For anyone interested in checking the working code that produces the behavior described:

    Code (CSharp):
    1. public class Overlap : MonoBehaviour
    2. {
    3.  
    4.    float xRandomPos, yRandomPos;
    5.    Vector3 finalRandomPos;
    6.    public int numToGenerate;
    7.    public List<GameObject> listOfObjects;
    8.    public GameObject background;
    9.    MeshCollider borders;
    10.  
    11. void Start()
    12.     {
    13.         borders = background.GetComponent<MeshCollider>();
    14.         WrappedCoroutine();
    15.     }
    16.  
    17.     /// <summary>
    18.     /// For the Button to click
    19.     /// </summary>
    20.     public void WrappedCoroutine()
    21.     {
    22.         StartCoroutine(Coroutine());
    23.     }
    24.  
    25.     /// <summary>
    26.     /// Main method
    27.     /// </summary>
    28.     /// <returns></returns>
    29.     public IEnumerator Coroutine()
    30.     {
    31.         //coroutine
    32.         WaitForSeconds wait = new WaitForSeconds(1f);
    33.  
    34.         //what to generate
    35.         int randomItemFromListIndex;
    36.         GameObject randomItemFromList;
    37. for (int i = 0; i < numToGenerate; i++)
    38.         {
    39.    
    40.                 //the object
    41.                 randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
    42.                 randomItemFromList = listOfObjects[randomItemFromListIndex];
    43.  
    44.                 //where
    45.                 xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
    46.                 yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
    47.                 finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
    48.                 //setUpperLower(finalRandomPos);
    49.        
    50.                 //randomItemFromList.transform.rotation same as Quaternion.identity?
    51.                 Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
    52.                 yield return wait;
    53.        
    54.         }
    55.     }
    56.  
    57.     /// <summary>
    58.     /// Restarts the current scene when the button is clicked
    59.     /// </summary>
    60.     public void Restart()
    61.     {
    62.         SceneManager.LoadScene("Overlap");
    63.     }
    64.  
    65. }
    Now, this below was the first attempt to modify the same code, so that it would not overlap, and it did not work:

    Code (CSharp):
    1. public class Overlap : MonoBehaviour
    2. {
    3.     //------------------------------new changes in attempt to avoid overlappping------------------------
    4.     public Collider2D[] colliders;
    5.     public float radius;
    6.     int safetyNet = 0;
    7.     //---------------------------------------------------------------------------------------------------
    8.  
    9.     float xRandomPos, yRandomPos;
    10.     Vector3 finalRandomPos;
    11.     public int numToGenerate;
    12.     public List<GameObject> listOfObjects;
    13.     public GameObject background;
    14.     MeshCollider borders;
    15.  
    16.     void Start()
    17.     {
    18.         borders = background.GetComponent<MeshCollider>();
    19.         WrappedCoroutine();
    20.     }
    21.  
    22.     /// <summary>
    23.     /// For the Button to click
    24.     /// </summary>
    25.     public void WrappedCoroutine()
    26.     {
    27.         StartCoroutine(Coroutine());
    28.     }
    29.  
    30.     /// <summary>
    31.     /// Main method
    32.     /// </summary>
    33.     /// <returns></returns>
    34.     public IEnumerator Coroutine()
    35.     {
    36.         //coroutine
    37.         WaitForSeconds wait = new WaitForSeconds(1f);
    38.  
    39.         //what to generate
    40.         int randomItemFromListIndex;
    41.         GameObject randomItemFromList;
    42.  
    43.  
    44.         for (int i = 0; i < numToGenerate; i++)
    45.         {
    46.    
    47.                 //the object
    48.                 randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
    49.                 randomItemFromList = listOfObjects[randomItemFromListIndex];
    50.  
    51.                 //where
    52.                 xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
    53.                 yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
    54.                 finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
    55.  
    56.                 //------------------------------new changes in attempt to avoid overlappping------------------------
    57.                 if (PreventOverlap(finalRandomPos))
    58.                 {
    59.                     Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
    60.                     yield return wait;
    61.                 }
    62.                 //---------------------------------------------------------------------------------------------------
    63.  
    64.         }
    65.     }
    66.  
    67.  
    68.  
    69.     //------------------------------new changes in attempt to avoid overlappping------------------------
    70.     bool PreventOverlap(Vector3 finalRandomPos)
    71.     {
    72.         //NB: it's an array
    73.         colliders = Physics2D.OverlapCircleAll(transform.position, radius);
    74.         for (int i = 0; i < colliders.Length; i++)
    75.         {
    76.             //checking the bounds of each collider and
    77.             //return false if the intended generating position falls within the bounds
    78.             Vector3 centerPoint = colliders[i].bounds.center;
    79.             float width = colliders[i].bounds.extents.x;
    80.             float height = colliders[i].bounds.extents.y;
    81.             //from which the main points can be derived
    82.             float left = centerPoint.x - width;
    83.             float right = centerPoint.x + width;
    84.             float top = centerPoint.y - height;
    85.             float bottom = centerPoint.y + height;
    86.    
    87.             //if it's falling within the left and right or top and bottom
    88.             if (finalRandomPos.x >= left && finalRandomPos.x <= right)
    89.             {
    90.                 //not here
    91.                 return false;
    92.             }
    93.             if(finalRandomPos.y >= top && finalRandomPos.y <= bottom)
    94.             {
    95.                 //not here
    96.                 return false;
    97.             }
    98.         }
    99.         return true;
    100.     }
    101.      //-----------------------------------------------------------------------------------------
    102.  
    103.     /// <summary>
    104.     /// Restarts the current scene when the button is clicked
    105.     /// </summary>
    106.     public void Restart()
    107.     {
    108.         SceneManager.LoadScene("Overlap");
    109.     }
    110.  
    111. }
    The code above does not produce any changes to the program. Any suggestions as to where it might have gone wrong? Alternatively, this below again is another unsuccessful attempt to modify the code:

    Code (CSharp):
    1. public class Overlap : MonoBehaviour
    2. {
    3.     //------------------------------new changes in attempt to avoid overlappping------------------------
    4.     //min------of the rectangle we want to check for collision
    5.     Vector2 upperLeft = new Vector2();
    6.     //max------of the rectangle we want to check for collision
    7.     Vector2 lowerRight = new Vector2();
    8.     //we will set the appropriate x and y for these when the time is right: more efficient from a memory perspective
    9.  
    10.     float xRandomPos, yRandomPos, halfWidth, halfHeight;
    11.  
    12.     //---------------------------------------------------------------------------------------------------
    13.  
    14.     Vector3 finalRandomPos;
    15.     public int numToGenerate;
    16.     public List<GameObject> listOfObjects;
    17.     public GameObject background;
    18.     MeshCollider borders;
    19.  
    20.     void Start()
    21.     {
    22.         borders = background.GetComponent<MeshCollider>();
    23.         WrappedCoroutine();
    24.     }
    25.  
    26.     /// <summary>
    27.     /// For the Button to click
    28.     /// </summary>
    29.     public void WrappedCoroutine()
    30.     {
    31.         StartCoroutine(Coroutine());
    32.     }
    33.  
    34.     /// <summary>
    35.     /// Main method
    36.     /// </summary>
    37.     /// <returns></returns>
    38.     public IEnumerator Coroutine()
    39.     {
    40.         //coroutine
    41.         WaitForSeconds wait = new WaitForSeconds(1f);
    42.  
    43.         //what to generate
    44.         int randomItemFromListIndex;
    45.         GameObject randomItemFromList;
    46.  
    47.         int i = 1;
    48.  
    49.         while(Physics2D.OverlapArea(upperLeft, lowerRight) != null && i< numToGenerate)
    50.         {
    51.    
    52.                 //the object
    53.                 randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
    54.                 randomItemFromList = listOfObjects[randomItemFromListIndex];
    55.  
    56.                 //where
    57.                 xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
    58.                 yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
    59.                 finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
    60.        
    61.                 //------------------------------new changes in attempt to avoid overlappping------------------------
    62.                 setUpperLower(finalRandomPos);
    63.                 //---------------------------------------------------------------------------------------------------
    64.  
    65.                 Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
    66.                     yield return wait;
    67.  
    68.             i++;
    69.         }
    70.     }
    71.  
    72.  
    73.  
    74.     //------------------------------new changes in attempt to avoid overlappping------------------------
    75.     void setUpperLower(Vector3 pos)
    76.     {
    77.         upperLeft.x = pos.x - halfWidth;
    78.         upperLeft.y = pos.y - halfHeight;
    79.         lowerRight.x = pos.x + halfWidth;
    80.         lowerRight.y = pos.y + halfHeight;
    81.     }
    82.      //-----------------------------------------------------------------------------------------
    83.  
    84.     /// <summary>
    85.     /// Restarts the current scene when the button is clicked
    86.     /// </summary>
    87.     public void Restart()
    88.     {
    89.         SceneManager.LoadScene("Overlap");
    90.     }
    91.  
    92. }
    Unlike the previous attempt, the code below does not produce any card at all.

    Any suggestion as to how I can modify the code and where I am understanding this wrong would be much appreciated!
     
    Last edited: Sep 22, 2020
  2. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    1.- Wow, so much code, that doesn't encourage anyone to help you.
    2.- Plz reference us wheres ur previous question.
    3.- What do you want exactly to do. It might explained at your previous post but not at this one. You wanna spawn x cards at random positions without overlapping anyone of them?
     
  3. Emolk

    Emolk

    Joined:
    Feb 11, 2014
    Posts:
    241
    You can use poisson disc sampling

     
  4. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    1. I'm not sure about 'anyone' but If you are not interested in checking the code, feel free to give suggestion on the topic as long as it's relevant without going through it. It's not some random code, but code that explains the behavior of the working program and the same modified code twice that shows how non-overlapping behavior has been attempted, as explained in the question. I posted them in case someone wanted to see the reasoning I am attempting and thought that might help others to understand the process.
    2. I don't have any previous questions on the topic. I meant that it is a common problem that has been asked previously and those were my attempts
    3. yes
     
    Last edited: Sep 22, 2020
  5. Emolk

    Emolk

    Joined:
    Feb 11, 2014
    Posts:
    241
    You could use a while loop for this however it's probably not a good approach as you're opening yourself up to infinite loops.

    Basically the syntax would be;

    Code (CSharp):
    1. for (int i = 0; i < NumToGenerate; i++)
    2. {
    3.     TrySpawnCard();
    4.  }
    5.  
    6. void TrySpawnCard(){
    7.  
    8.     var randPosition = //pick random position
    9.  
    10.     bool spawned = false;
    11.  
    12.     while(!spawned){
    13.        
    14.         foreach (var card in cardsAlreadySpawned)
    15.         {
    16.             if(Vector2.Distance(randPosition, card.transform.position) > minimumDistance)
    17.                 continue
    18.             else{
    19.                 spawned = true;
    20.                 SpawnCard(randPosition);
    21.                 return;
    22.             }
    23.         }
    24.     }
    25. }
    26.  
    27. void SpawnCard(position){
    28.     //Do spawning here
    29.     // Add it to list of cardsAlreadySpawned
    30. }
    Again I would look for other solutions here this is pretty messy.

    For a collision based approach (convert it to C#):
    https://answers.unity.com/questions/385857/instantiating-objects-at-random-positions-with-a-c.html
     
    Last edited: Sep 24, 2020