-2

I'm a new C# programmer here in the early stages of creating a project in Unity where you play as a microbe that needs to eat blue food pellets to grow and survive. I've got the blue food pellets to spawn randomly across the map but I want to add a delay because too much is spawning at once. This is what I've attempted to do so far. Any help would be appreciated!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;

public class Spawner : MonoBehaviour
{
    public GameObject food;
    public async void Wait(float duration)
    {
        Vector3 randomSpawnPosition = new Vector3(Random.Range(-50, 50), 1, Random.Range(-50, 50));
        Instantiate(food, randomSpawnPosition, Quaternion.identity);
        await Task.Delay((int)duration * 1000);
    }
    // Update is called once per frame
    void Update()
    {
        async void Wait(float duration);


    }

    
}

What I've tried:

Putting the delay function in the update function. The program just gets confused and thinks I'm trying to call the function.

Calling the function after combining all my code into the one function, the program rejects this.

  • 1
    That seems both needlessly complicated and wrong. Why don't you just keep track of the time since last spawn in a member variable and only spawn if enough time has passed since then? – UnholySheep Nov 02 '22 at 17:27

2 Answers2

1

Like the default code snippet says, Update runs every frame. Using Task.Delay to delay events would still spawn objects with the same frequency, they would only start spawning delayed.

The typical way to do this in Unity is to use a coroutine.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    [SerializeField] GameObject food;

    protected void OnEnable()
    {
        StartCoroutine(SpawnFoodRoutine());
    }

    IEnumerator SpawnFoodRoutine()
    {
        while(enabled)
        {
            SpawnFood();

            var waitTime = Random.Range(1f, 5f);
            yield return new WaitForSeconds(waitTime);
        }
    }

    void SpawnFood()
    {
        Vector3 randomSpawnPosition = new Vector3(
            Random.Range(-50f, 50f), 
            1f, 
            Random.Range(-50f, 50f));

        Instantiate(food, randomSpawnPosition, Quaternion.identity);
    }
}
Scabbage
  • 11
  • 2
-1

I have made this prefab called “pellet”, then I have created a new gameObject called “SpawnManager” and, finally, added this script to SpawnManager:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class SpawnPellet : MonoBehaviour
{
 
    public GameObject prefab;
    public bool canSpawnNewPellet = true;
    public float delay;
 
    void Update(){
        if(canSpawnNewPellet){
            Invoke("SpawnNewPellet", delay);
            canSpawnNewPellet = false;
        }
    }
 
 
    void SpawnNewPellet()
    {
        GameObject instance = Instantiate(prefab);
        instance.transform.position = new Vector3(Random.Range(0,10), Random.Range(0,10), 0);
        canSpawnNewPellet = true;
    }
}

The I have dragged and dropped/edited values on the fields in the inspector (Prefab, canSpawnNewPellet and Delay). Those are public fields inside the script, so you can populate them drag and dropping directly from your assets folder.

Assets, Hierarchy & Inspector

Hit play and you have a new spawn every X seconds where X is the value of delay in seconds.

Screenshot of the game executing after 21 seconds.

Screenshot

What does it do? Every frame it evaluates if can spawn a new pellet (bool canSpawnNewPellet). If it can, then it starts an invocation of another method with X seconds (and mark the bool as false since we don’t want to call more invocations during de instantiation of our first sample).

For more references: https://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html

Edited: typo.

Jinwe
  • 9
  • 2
  • This seems unnecessarily complicated .. if you really want to go the `Invoke` way you would rather simply use [`InvokeRepeating`](https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html) ... – derHugo Nov 03 '22 at 15:05