Jacob Allen
Jacob Allen

Reputation: 57

Wait for a function to finish executing before the start method stops

Hi I am working on game that uses random terrain and I want to spawn objects onto that terrain. To do this, I have created what I have called the Surface Populator Script.

This is the script:

public SurfaceSpawnerData spawnerData;

private float randomX;
private float randomZ;
private Renderer r;

void Start()
{
    r = GetComponent<Renderer>();
    for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
    {
        spawnerData.spawnableObjects[i].currentObjects = 0;
    }
    spawnerData.SpawnedObjects.Clear();

    SpawnObjects();
}

void Update()
{

}

void SpawnObjects()
{
    RaycastHit hit;

    for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
    {
        int currentObjects = spawnerData.spawnableObjects[i].currentObjects;
        int numOfObjects = spawnerData.spawnableObjects[i].numberOfObjects;

        if (currentObjects != numOfObjects)
        {
            if (Physics.Raycast(new Vector3(randomX, r.bounds.max.y + 5f, randomZ), -Vector3.up, out hit))
            {
                randomX = Random.Range(r.bounds.min.x, r.bounds.max.x);
                randomZ = Random.Range(r.bounds.min.z, r.bounds.max.z);

                if (hit.point.y >= spawnerData.spawnableObjects[i].spawnerStartHeight && hit.point.y <= spawnerData.spawnableObjects[i].spawnerEndHeight)
                {
                    spawnerData.SpawnedObjects.Add(Instantiate(spawnerData.spawnableObjects[i].spawnablePrefab, hit.point, Quaternion.identity));
                    spawnerData.spawnableObjects[i].currentObjects += 1;
                }
            }
        }
    }
}

The script also gains its data from a scriptable object:

[CreateAssetMenu]
public class SurfaceSpawnerData : ScriptableObject
{
    public SpawnableObjects[] spawnableObjects;
    public List<GameObject> SpawnedObjects; 

    [System.Serializable]
    public class SpawnableObjects
    {
        public GameObject spawnablePrefab;
        public float spawnerStartHeight = 2f;
        public float spawnerEndHeight;
        public int currentObjects;
        public int numberOfObjects;
    }
}

This script currently works perfectly fine when placed inside the update method, however I do not want to do this due to its affect on performance. Therefore I am wondering if there is a way to stop the Unity start method from exiting until my SpawnObjects() function has stopped running. If this is not possible if you have any other ideas on how I run this only once without using the update function let me know.

I am relatively new to c# as a language and I'm sorry if there is an easy fix that I have missed. Any help would be appreciated. Thanks.

Upvotes: 1

Views: 58

Answers (1)

derHugo
derHugo

Reputation: 90779

Since SpawnObjects is a synchronus method Start will not return until SpawnObjects finished anyway.

As far as I understand your issue is rather that anything from Physics is not available during initialization (Awake, OnEnable, Start) but only within or after the Physics block (see ExecutionOrder) so e.g. in a method like FixedUpdate or Update.


So to answer your question: You could use a Coroutine and WaitForFixedUpdate in order to make your Instantiation:

void Start()
{
    r = GetComponent<Renderer>();
    for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
    {
        spawnerData.spawnableObjects[i].currentObjects = 0;
    }
    spawnerData.SpawnedObjects.Clear();

    StartCoroutine(DoInstantiate());
}

private IEnumerator DoInstantiate()
{
    // wait until Physics are initialized
    yield return new WaitForFixedUpdate();

    SpawnObjects();
}

or as you can see in ScriptReference/Coroutine you can make this shorter by directly making the Start a routine e.g. like

IEnumerator Start()
{
    r = GetComponent<Renderer>();
    for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
    {
        spawnerData.spawnableObjects[i].currentObjects = 0;
    }
    spawnerData.SpawnedObjects.Clear();

    // wait until Physics are initialized
    yield return new WaitForFixedUpdate();

    SpawnObjects();
}

Upvotes: 2

Related Questions