Search code examples
c#unity-game-enginecoroutine

Synchronize main loop (Spawner.cs) with subloop on Prefab


I'm working on Unity3d project where the floor has to unfold gradually. I created a script FloorModule.cs where using coroutine the floor tiles are laying out gradually. Each next module has to unfold right after previous is completed. There for I created Spawner.cs to loop a new FloorModule.cs right after previous one is completed.

I can't seem to get my head around how to use coroutine to synchronize the mainloop (Spawner.cs) with subloop on prefab (FloorModule.cs).

Here is the link to the example https://1drv.ms/u/s!AkVZpIE6f1GV4M5Ju7G5zPOrQcCe8w?e=QrghRT

P.S. In given example, as loop goes forward I'm using "Reference.cs" class to change some variable values .

FloorModule.cs

    public class FloorModule : MonoBehaviour
    {
        public float zSpacer = 0f;

        public int instPrefabCount;
        public Transform spawnPoint;
        public int lenght = 15;
        public int width = 5;

        public GameObject floorTiles;

        void Start()
        {
            spawnPoint = GetComponent<Transform>();

            StartCoroutine(FwFloorDelay(spawnPoint));
        }

        public IEnumerator FwFloorDelay(Transform origin)
        {
            for (int l = 0; l < lenght; l++)
            {
                float xAngle = 90;
                float yPos = 0;
                float zPos = 0 + l;

                for (int w = 0; w < width; w++)
                {
                    int xSelection = Random.Range(0, 6);
                    GameObject xFloor = Instantiate(floorTiles, origin);

                    TileStatusNames(xFloor, l, w);

                    // defining positiona and angles
                    float xPos = w + (zSpacer * w);
                    xFloor.transform.localEulerAngles = new Vector3(xAngle, 0, 0);
                    xFloor.transform.localPosition = new Vector3(xPos, yPos, zPos);

                    yield return new WaitForSeconds(.05f);

                }
            }

Spawner.cs

    public class Spawner : MonoBehaviour
    {
        public GameObject FloorModPrefab;
        public References[] referenceScript;

        void Start()
        {
            StartCoroutine(SpawnModules());
        }

        IEnumerator SpawnModules()
        {
            for (int i = 0; i < referenceScript.Length; i++)
            {
                referenceScript[i].instance =
                    Instantiate(FloorModPrefab, referenceScript[i].ref_spawnPoint.position, referenceScript[i].ref_spawnPoint.rotation);

                referenceScript[i].ref_instFloorModCount = i + 1;
                referenceScript[i].Setup();
                yield return new WaitForSeconds(5f);
            }
        }
    }

References.cs

    [Serializable]
    public class References
    {
        FloorModule prefabObjScript;
        public GameObject instance; 

        public int ref_instFloorModCount;
        public Transform ref_spawnPoint;
        public int ref_Width = 5;
        public int ref_Lenght = 15;

        public void Setup()
        {
            // Get references to the components.
            prefabObjScript = instance.GetComponent<FloorModule>();

            // Set the player numbers to be consistent across the scripts.
            prefabObjScript.instPrefabCount = ref_instFloorModCount;
            prefabObjScript.spawnPoint = ref_spawnPoint;
            prefabObjScript.width = ref_Width;
            prefabObjScript.lenght = ref_Lenght;
        }
    }

I tried to use coroutines unfortunately in given context I realize it's impossible for me to resolve this task.


Solution

  • You can yield a coroutine from within another coroutine.

    Changes to your Code

    In References change public GameObject instance; to public FloorModule instance;
    In Spawner change public GameObject FloorModPrefab; to public FloorModule FloorModPrefab;
    Remove the code from Start of FloorModule.

    Modify FwFloorDelay to

    public IEnumerator FwFloorDelay(Transform origin = null)
    {
        if (origin == null)
        {
            origin = transform;
        }
        ...
    }
    

    In SpawnModules, chain the floor delay coroutine

    IEnumerator SpawnModules()
    {
        for (int i = 0; i < referenceScript.Length; i++)
        {
            ...
            yield return referenceScript[i].instance.FwFloorDelay();
        }
    }