Search Unity

Question List doesn't want add more than one instantiated prefab?

Discussion in 'Scripting' started by StevieVB, Jun 5, 2023.

  1. StevieVB

    StevieVB

    Joined:
    Aug 10, 2020
    Posts:
    2
    So i've been messing around with unity for a while and started doing my own little game.

    Basically the concept is pretty much the "I love Hue game" where there are different "cubes" or "squares" in a different gradient that you have to sort depending on colour. I've done the swapping and colour gradient and spawnroutine, now I want the cubes to be spawned in then "randomized" so the player has to sort them back to the original state, I planned on doing this with a list.

    The problem is that everytime I create a GameObject foo and then two lines later do fooList.Add(foo) it doesn't add more than 1 item to the list, even though the whole thing is in a for loop.

    I have the relevant code underneath, any help would be greatly appreciated!

    Debugger returns every time: "1 Item in list"
    and when I try to do anything with the list it returns: "Index was out of range" error.

    I tried using a FindGameobject etc. tagging the prefab etc. but the list seems to not want to cooperate?

    Code (CSharp):
    1. public List<GameObject> spawnedSquares = new List<GameObject>();
    2.  
    3. /*Code inbetween...*/
    4.  
    5. IEnumerator SpawnRoutine()
    6.     {
    7.         int i;
    8.         float squareLocX = spawnPoint.x + 0.75f;
    9.         float squareLocY = spawnPoint.y - 0.75f;
    10.         for (i = 0; i < numberOfSquares; i++)
    11.         {
    12.             if (squareLocX == 3.75f)
    13.             {
    14.                 squareLocX = -2.25f;
    15.                 squareLocY -= 1.5f;
    16.             }
    17.             Vector2 spawnHere = new Vector2(squareLocX, squareLocY);
    18.             squareLocX += 1.5f;
    19.             GameObject newSquare = (GameObject)Instantiate(square, spawnHere, Quaternion.identity);
    20.             newSquare.gameObject.name = "Square" + i;
    21.             if (i < numberOfSquares)
    22.             {
    23.                 newColor = Color.Lerp(Color.red, Color.green, i/ 24f);
    24.             }
    25.             Debug.Log(newSquare.name);
    26.             spawnedSquares.Add(newSquare);
    27.             yield return new WaitForSeconds(0.0f);
    28.         }
    29.     }
    30.  
    31. public void Randomize()
    32.     {
    33.         if (spawnedSquares.Count <= 1)
    34.         {
    35.             Debug.Log("1 item in list");
    36.         }
    37.         else if (spawnedSquares.Count > 1)
    38.         {
    39.             Debug.Log("more than 1");
    40.         }
    41.  
    42.         square1ToSwap = spawnedSquares[0];
    43.         square2ToSwap = spawnedSquares[1];
    44.         SwapOnCommand();
    45.     }
    46.  
    47. void Start()
    48.     {
    49.         StartCoroutine(SpawnRoutine());
    50.         Randomize();
    51.     }
    52.  
    53.  
    PS: first time poster, so go easy on me if I've made some mistake here...
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,908
    You have indeed made a rookie mistake.

    Code (CSharp):
    1. void Start()
    2.     {
    3.         StartCoroutine(SpawnRoutine());
    4.         Randomize();
    5.     }
    You are starting the coroutine and then IMMEDIATELY running Randomize. The coroutine will run up to the first yield statement (which happens to be line 27 in your snippet) after a single element has been added to the list. After that, Randomize will run, at which point there is only one element in the list.

    After Randomize runs, the coroutine will continue over the next frames until it is finished at which point multiple items may be in the list (assuming numberOfSquares is more than 1).

    If you want to run Randomize after the entire coroutine finishes, put the call at the end of the coroutine, for example between lines 28 and 29.
     
    Bunny83, StevieVB and Kurt-Dekker like this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,674
    Line 49 starts the coroutine, which only runs until the first yield. (see below for more).

    That means it only gets one item in before line 50 runs.

    Perhaps put Randomize inside your coro?

    Here's more reading:

    Coroutines in a nutshell:

    https://forum.unity.com/threads/des...en-restarting-the-scene.1044247/#post-6758470

    https://forum.unity.com/threads/proper-way-to-stop-coroutine.704210/#post-4707821

    Splitting up larger tasks in coroutines:

    https://forum.unity.com/threads/bes...ion-so-its-non-blocking.1108901/#post-7135529

    Coroutines are NOT always an appropriate solution: know when to use them!

    "Why not simply stop having so many coroutines ffs." - orionsyndrome on Unity3D forums

    https://forum.unity.com/threads/things-to-check-before-starting-a-coroutine.1177055/#post-7538972

    https://forum.unity.com/threads/heartbeat-courutine-fx.1146062/#post-7358312

    Our very own Bunny83 has also provided a Coroutine Crash Course:

    https://answers.unity.com/questions...ected.html?childToView=1749714#answer-1749714
     
    Bunny83 and StevieVB like this.
  4. StevieVB

    StevieVB

    Joined:
    Aug 10, 2020
    Posts:
    2
    Thanks a lot! Makes complete sense when you look at it now xD
     
    Kurt-Dekker likes this.