Unity3D C# level generating script not working as intended

Viewed 27

Basically, I wrote this level generating script for an endless runner game in Unity. The problem is that the boards generate way too fast for any mobile device to handle. To prevent this, I added this line of code:

yield return new WaitForSeconds(2);

But for some reason, my script keeps generating boards as fast as it can, not waiting for 2 seconds.

I tried toggle commenting the line, but whatever I tried didn't work. Can anyone take a look?

Here's the full script:

using System.Collections.Generic;
using UnityEngine;

public class GenerateLevel : MonoBehaviour
{
    public GameObject[] section;
    public int zPos = 19;
    public bool creatingSection = false;
    public int secNum;
    
    void Update()
    {
        if (creatingSection == false)

            creatingSection = true;
            StartCoroutine(GenerateSection());
    }


    IEnumerator GenerateSection()
    {
        secNum = Random.Range(0, 3);
        Instantiate(section[secNum], new Vector3(0, 0, zPos), Quaternion.identity);
        zPos += 38;
        yield return new WaitForSeconds(2);
        creatingSection = false;
    }
}
1 Answers

This is a typical typo: An if without curly braces ({ }) only applies to the very next single expression so your

if (creatingSection == false)
    creatingSection = true;
    StartCoroutine(GenerateSection());

basically reads

if (creatingSection == false)
{
    creatingSection = true;
}
StartCoroutine(GenerateSection());

which means you start a coroutine each and every frame!

what you would want is rather

if (creatingSection == false)
{
    creatingSection = true;
    StartCoroutine(GenerateSection());
}

Anyway, instead of risking this at all and poll check a flag every frame what you rather should do is have a proper method for starting your routine

public class GenerateLevel : MonoBehaviour
{
    [Header("Assets")]
    public GameObject[] section;

    [Header("Settings")]
    public int zPos = 19;
    
    private bool isGenerating;
    
    // This atttribute adds an entry to the context menu of this component
    // in the Inspector so you can still run it from there for testing
    // see https://docs.unity3d.com/ScriptReference/ContextMenu.html
    [ContextMenu(nameof(StartGenerating))]
    public void StartGenerating()
    {
        // also prevent multiple concurrent routines
        if(isGenerating) return;

        StartCoroutine(GenerateSection());
    }

    IEnumerator GenerateSection()
    {
        if(isGenerating) yield break;

        isGenerating = true;

        // I would go fully dynmic here and intad of hoping that there are 3 elements in "section"
        // rather rely on its actual length 
        // => you can easily add and remove items via the Inspector and it still works without touching the code
        var secNum = Random.Range(0, section.Length);
        Instantiate(section[secNum], new Vector3(0, 0, zPos), Quaternion.identity);
        zPos += 38;

        yield return new WaitForSeconds(2);

        isGenerating = false;
    }
}
Related