Search code examples
c#unity-game-engineinstantiationcoroutine

Unity - Instantiated objects spawn on the same position in Coroutine, while instantiate them directly do spawn correctly


What i want to achieve:

Im creating a procedural generated city. I got the roads working, together with the spawning of the houses, they spawn along the road and dont get spawned if they are colliding with either the road and/or another building. Now since i sometimes i want to load a big city, this costs a lot of computing time, so i wanted to put in a Coroutine to slowly load in all the houses. (Please tell me if there is a better way, or a "correct" way, this is the only thing that i knew that could work).

What i did / Problem:

So what i did, is all the segments i use to create a house i put in a list, and once all the houses are pregenerated (not spawned/instantiated yet) i want to use the coroutine to spawn them individually. But whenever i use the coroutine to spawn them, they spawn inside eachother. While if i spawn them directly from their script (still using the list) they do spawn correctly, i have no clue what i am doing wrong and how to fix this.

public void Spawner(Vector3 buildingPosition, Quaternion buildingRotation, int buildingHeight, GameObject buildingParent, LayerMask m_LayerMask, BuildingGenerator buildGenerator)
    {
        GameObject baseBuilding = buildingBase[Random.Range(0, buildingBase.Count)];
        baseBuilding.transform.position = buildingPosition;
        baseBuilding.transform.rotation = buildingRotation;

        Debug.Log(baseBuilding.transform.position);

        Collider[] hitColliders = Physics.OverlapBox(baseBuilding.transform.position, baseBuilding.GetComponentInChildren<Renderer>().bounds.extents /2, Quaternion.identity, m_LayerMask);
        if (hitColliders.Count() > 1)
        {
            return;
        }
        buildGenerator.Segments.Add(baseBuilding);
        buildingPosition.y += baseBuilding.GetComponentInChildren<Renderer>().bounds.max.y - buildingPosition.y;

        for (int i = 0; i <= buildingHeight; i++)
        {
            buildingRotation *= Quaternion.Euler(0, 0, 0);
            GameObject middleBuilding = buildingMiddle[Random.Range(0, buildingMiddle.Count)];
            middleBuilding.transform.position = buildingPosition;
            middleBuilding.transform.rotation = buildingRotation;
            //buildGenerator.Segments.Add(middleBuilding);

            buildingPosition.y += middleBuilding.GetComponentInChildren<Renderer>().bounds.max.y - buildingPosition.y;

        }
        if (buildingRoof.Count != 0)
        {
            GameObject roofBuilding = buildingRoof[Random.Range(0, buildingRoof.Count)];
            roofBuilding.transform.position = buildingPosition;
            roofBuilding.transform.rotation = buildingRotation;
            buildGenerator.Segments.Add(roofBuilding);
        }
        Instantiate(buildGenerator.Segments[1]);                //If i use this, they spawn on the correct place.
        Debug.Log(buildGenerator.Segments.Count);

    }
    {
        StartCoroutine(LoadSegments(buildingParent));
    }
    public IEnumerator LoadSegments(GameObject buildingParent)
    {
        for (int i = 0; i < Segments.Count; i++)
        {
            GameObject SpawnedSegment = Instantiate(Segments[i]);
            //SpawnedSegment.transform.parent = buildingParent.transform;
            yield return new WaitForEndOfFrame();
        }
    }

Extra info:

I make use of 3 scripts to spawn the whole city, the roadGenerator, which will spawn the roads, those road points get stored in a list. After the roads are generater the roadgenerator will call the building Generator. The building generator will go through the whole list of all the roads, and create buildings aside them, the buildings are created via a 3rd script (not instantiated). The building script, this script contains the building segments, and will piece them together and also check for collisions (First code block). Once these buildings are all created and put into a list, the buildingGenerator will start the coroutine and instantiate all these buildings (thus on the wrong position)(Second code block).

Hope i provided enough information, else id be happy to provide more.


Solution

  • Okay so i finally got it working. The problem was not at the coroutine, but at the list. My code would constantly override my list objects. So i created a new script, with basic attributes like the object, the position and rotation. So then i add those new scripts to the list, and spawn them in the coroutine. (In my comment i said i had some other problems after i fixed this, this is because i used .bounds.max.y, while i should have used .bounds.size.y. This is thus also the fix for that).

    I hope someone in the future might find this helpful!