Using WaitForSeconds?

Hi, I’m new to Unity and I’m trying to make it so that when you press the space bar, it spawns an object. It worked before, but it would spawn enemies every frame. I attempted to fix this by making it so that you need to wait a second before another enemy would spawn, but now it’s not doing anything at all. Here’s what I have, it would be great if you could help.

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

public class Test : MonoBehaviour
{
public GameObject prefab;
// Use this for initialization
void Start()
{

}

// Update is called once per frame
void Update()
{

}

void Spawn()
{
if (Input.GetKey(KeyCode.Space))
{
Instantiate(prefab, transform.position, transform.rotation);
StartCoroutine(“waitOneSecond”);
} }
IEnumerator waitOneSecond()
{
yield return new WaitForSeconds(1);
}

}

Use code tags:

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

public class Test : MonoBehaviour
{
    public GameObject prefab;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }

    void Spawn()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            Instantiate(prefab, transform.position, transform.rotation);
            StartCoroutine("waitOneSecond");
        }
    }
    IEnumerator waitOneSecond()
    {
        yield return new WaitForSeconds(1);
    }

}

I’m not sure how this worked before… this really doesn’t do anything.

Nothing calls the function ‘Spawn’.

And your code instantiates something, then starts a coroutine which just waits for a second and does nothing else.

I presume what you want is that on the press of space Spawn gets called and it waits 1 second and then instantaites something. Like this:

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

public class Test : MonoBehaviour
{
    public GameObject prefab;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            StartCoroutine(Spawn());
        }
    }

    IEnumerator Spawn()
    {
        yield return new WaitForSeconds(1);
        Instantiate(prefab, transform.position, transform.rotation);
    }
 
}

Note there is alternatives to this as well. Such as the simpler Invoke method that calls a method after a delay, avoiding having to do the coroutine all together:

1 Like

Okay, cool, thanks.

@lordofduct wouldn’t that still spawn enemies every frame for as long as the player holds the ke, but just delayed by 1 second? Also I think he wants the enemy spawn immediately, but preventing the next one spawning for 1 second

maybe something more along the lines of

public class Test : MonoBehaviour
{
    public GameObject prefab;
    // Use this for initialization
    void OnEnable()
    {
        StartCoroutine(SpawnHandler());
    }

    IEnumerator Spawn()
    {
        while(true)
        {
            if(Input.GetKey(KeyCode.Space))
            {
                Instantiate(prefab, transform.position, transform.rotation);
                yield return new WaitForSeconds(1);
            }
            else
            {
                yield return null;
            }
        }
    }
}

waiting a second before spawning, or spawning immeadiately and then preventing the next for a second… if you need the other behaviour then all it comes down to is swapping the order of Instantiate and the WaitForSeconds.

I didn’t necessarily put a lot of effort into it. Yeah, probably should be GetKeyDown first and foremost instead of GetKey. Beyond that, I have no idea what the OP actually wants.

When I comment on threads I try to put as much effort into my response as I feel the OP puts into their question. OP here put in enough to get a basic reorganize of the existing code to actually operate in some functional manner (I literally just ctrl+x ctrl+c the parts around to work). Beyond that, well, going to need to offer up some more effort on their end and give more detail as to what they expect.

If I was going to rewrite it, it’d probably be something like this. I’d avoid coroutines all together if only because I wouldn’t want the GC overhead. Since we need to check keydown every update, just use Update for that and consume that overhead instead since it’s needed anyways. It’s a trivial script, so the odd writing style is pretty self evident. This would be more what I’d call an “art script”, some trivial and simplisticly structured for a basic effect. This would also facilitate refactoring if necessary, if we decided the behaviour wasn’t what we wanted. Like if we decided it doesn’t cache button presses while waiting to spawn… we just clamp the _cache variable.

The result would be something like:

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

public class Test : MonoBehaviour
{
    public GameObject prefab;
    public float SpawnDelay = 1f;
    private int _cache = 0;
    private float _t = 0f;

    void Update()
    {
        if (this.prefab == null) return;
   
        if(_cache > 0)
        {
            _t -= Time.deltaTime;
            if(_t <= 0f)
            {
                Instantiate(prefab, transform.position, transform.rotation);
                _cache--;
                _t = this.SpawnDelay;
            }
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            if(_cache == 0) _t = this.SpawnDelay;
            _cache++;
        }
    }
 
}

But that’s just me. And that’s a type of behaviour I’d expect for a spawn on press space bar type thing.