Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Set WaitForSeconds() to zero still make Instantiate delay?

Discussion in 'Scripting' started by Ultimate360, Aug 4, 2017.

  1. Ultimate360

    Ultimate360

    Joined:
    Oct 28, 2016
    Posts:
    27
    Hi, I have a problem about WaitForSeconds when editor set zero delay. It is not the result I was expecting, even set to zero, it's like the instantiate of object delay maybe about 0.02 seconds? Can someone help me with a solution?

    Here's the snapshot (some code parts and result) I was actually working: (Image – left: without delay; right: with WaitForSeconds() set to zero)


    But let's just go here; here's my simplified testing script:
    CoroutineTest.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class CoroutineTest : MonoBehaviour {
    6.  
    7.     public Transform spawnPoint;
    8.     public float rotationOffset;
    9.     private float _rotationOffset;
    10.     public int shootAmount = 0;
    11.     [Range(0,1)] public float shootDelay = 0f;
    12.  
    13.     // Update is called once per frame
    14.     void Update () {
    15.         if (Input.GetKeyDown (KeyCode.Space))
    16.             StartCoroutine (Test1 (1));
    17.         if (Input.GetKeyDown (KeyCode.E))
    18.             StopCoroutine (Test1 (2));
    19.     }
    20.  
    21.     IEnumerator Test1 (int code) {
    22.         float setRotation = _rotationOffset;
    23.         if (code == 1)
    24.         {
    25.             _rotationOffset += rotationOffset;
    26.             for (int i = 0; i < shootAmount; i++) {
    27.                 Instantiate (spawnPoint, transform.position, transform.rotation * Quaternion.Euler (0f, setRotation, 0f));
    28.                 //work expected: 0.1f, 0.2f, 1, 2, 2.5f except 0 (zero)...
    29.                 yield return new WaitForSeconds (shootDelay);
    30.                 //yield return new WaitForSeconds (0);
    31.             }
    32.         }
    33.         else
    34.         {
    35.             Debug.Log ("Stop CoRoutine!");
    36.         }
    37.         yield return null;
    38.     }
    39. }

    I attach a zip file for this ^ StartCoroutineTesting.zip

    Thank you so much, your help is appreciated!
     

    Attached Files:

  2. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    I assume this is the code with issue? and by issue I mean, there is no pause between each shootAmount. so this is like 6 shoots in a gun. and you are trying to build a cool down system to delay how often the player can shoot his gun.
    1. for (int i = 0; i < shootAmount; i++) {
    2. Instantiate (spawnPoint, transform.position, transform.rotation * Quaternion.Euler (0f, setRotation, 0f));
    3. //work expected: 0.1f, 0.2f, 1, 2, 2.5f except 0 (zero)...
    4. yield return new WaitForSeconds (shootDelay);
    5. //yield return new WaitForSeconds (0);
    6. }

    the issue is really in the Update(), the spacebar is creating multiple instances of the Coroutine. and there for the player can shoot when ever he wants. you might have 20 or 50 coroutines running at the same time.
     
  3. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    try a bool to stop the player from pressing the space bar

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class CoroutineTest : MonoBehaviour {
    6.  
    7.     public Transform spawnPoint;
    8.     public float rotationOffset;
    9.     private float _rotationOffset;
    10.     public int shootAmount = 0;
    11.     [Range(0,1)] public float shootDelay = 0f;
    12.     private bool cooldown = false;
    13.  
    14.     // Update is called once per frame
    15.     void Update () {
    16.         if (Input.GetKeyDown (KeyCode.Space) && cooldown == false)
    17.             StartCoroutine (Test1 (1));
    18.         if (Input.GetKeyDown (KeyCode.E))
    19.             StopCoroutine (Test1 (2));
    20.     }
    21.  
    22.     IEnumerator Test1 (int code) {
    23.         float setRotation = _rotationOffset;
    24.         if (code == 1)
    25.         {
    26.           cooldown = true;
    27.             _rotationOffset += rotationOffset;
    28.             for (int i = 0; i < shootAmount; i++) {
    29.                 Instantiate (spawnPoint, transform.position, transform.rotation * Quaternion.Euler (0f, setRotation, 0f));
    30.                 //work expected: 0.1f, 0.2f, 1, 2, 2.5f except 0 (zero)...
    31.                 yield return new WaitForSeconds (shootDelay);
    32.                 //yield return new WaitForSeconds (0);
    33.             }
    34.           cooldown = false;
    35.         }
    36.         else
    37.         {
    38.             Debug.Log ("Stop CoRoutine!");
    39.         }
    40.         yield return null;
    41.     }
    42. }
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    That's also not how you use StopCoroutine (that whole thing looks goofy).

    StartCoroutine gives you back the Coroutine you started so you can skip the bool and just check if one is already working
    Code (csharp):
    1.  
    2. Coroutine shoot;
    3.  
    4. void Update()
    5. {
    6.     if (Input.GetKeyDown(...) && shoot == null)
    7.     {
    8.         shoot = StartCoroutine(Test());
    9.     }
    10.     else if (Input.GetKeyDown(...) && shoot != null)
    11.     {
    12.         StopCoroutine(shoot);
    13.         shoot = null;
    14.     }
    15. }
    16.  
     
    Ultimate360 likes this.
  5. Ultimate360

    Ultimate360

    Joined:
    Oct 28, 2016
    Posts:
    27
    Hi, thank you for the reply... but sorry for the lack of detail what I really want to achieved; I only concern is that WaitForSeconds() can't go below 0.02 seconds, is that right? I use WaitForSeconds(), not for player, but for enemy/AI trigger to do hell bullet patterns or with style: for example
    https://www.youtube.com/results?search_query=game+hell+bullet

    I want an option for to shoot parallel bullets with or without delay, I once use WaitForSeconds() for spawning enemies with gaps or instantly spawn all at once (WaitForSeconds(spawnGap) as spawnGap = 0), or they just seem to be but not... not until I make this HellBulletManager.cs:



    In short, my only concern is that WaitForSeconds() can't go instant? There will always be at least 0.02 seconds delay?
    If that's the case, can't be done; I'll just have to do the cheap way solution like:
    Code (CSharp):
    1. if (linearDelay > 0)
    2.     yield return new WaitForSeconds(linearDelay);
    What do you think, guys? ^

    P.S. Thank you, now I know how to use StopCoroutine(); :D not using to my actual script HellBulletManager.cs, I just trying it to my testing script...
     

    Attached Files:

    Last edited: Aug 5, 2017
  6. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Unity's documentation is a little vague here:

    So, my interpretation of that is even if the value is 0, it still waits for at least one frame.

    So yes, doing an if check first seems like the way to go if you want to immediately continue if the value is 0.
     
    kelman7000, Railon23 and Ultimate360 like this.
  7. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,919
  8. Solihin100

    Solihin100

    Joined:
    Mar 7, 2021
    Posts:
    8

    Yup, bingo. Just tested it.

    -----------------------------------------------------------------------------------
    using System.Collections;
    using UnityEngine;

    public class WaitForSecondsTest : MonoBehaviour
    {
    public float WaitTime;
    private float TimeStamp;

    void Start() => StartCoroutine(Wait());

    private IEnumerator Wait()
    {
    TimeStamp = Time.time;

    for (int i = 1; i <= 1000; i++)
    {
    yield return new WaitForSeconds(WaitTime);
    Debug.Log((Time.time - TimeStamp).ToString() + " has passed");
    }
    }
    }
    -----------------------------------------------------------------------------------