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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How to give an object a start delay

Discussion in 'Scripting' started by PVisser, Sep 20, 2016.

  1. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    For the past few hours I've been trying to recreate a GIF (which is how I learn) that consists out of balls that move to the opposite side and back in a loop. Every second a new ball starts moving and in the end it becomes one moving circle.




    Now my problem is that I set all the balls in the level, but I need them to activate/start moving/show up with a delay that I can set. I'm no programmer and I use scripts by duct taping code together from all over the place but I can't seem to find a solution to this. I did find out how to delay a moving platform (example) at points when it has already started moving but that is not quite what I need here.

    I have the impression that this shouldn't be as hard as I'm finding it to be. Any way to simply have a script on an object that says: "stay where you for ... seconds" or "when the level is loaded spawn after ... seconds" ?
     
    Last edited: Sep 20, 2016
  2. gibbie_learnersedge

    gibbie_learnersedge

    Joined:
    Aug 11, 2016
    Posts:
    25
    You could create a sprite that switch after a couple of ms. You can create a class where the sprite is an array. Then create a coroutine func which will switch sprite after yield.
     
  3. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Depending on exactly how the GameObject is drawing something will make the details slightly different (Is it a 2D Sprite with an Image Script, is it a 3D object with a MeshRenderer,etc). But here is code that will make an object wait X Seconds then turn on.

    Code (CSharp):
    1. void Awake()
    2. {
    3.        Image image = GetComponent<Image>();
    4.        image.enabled = false;   // this turns off the picture
    5.        // if you had a MeshRenderer you could do the same thing:
    6.       // You would only do ONE of these not both. depending on whats
    7.        // on your object
    8.        MeshRenderer renderer = GetComponent<MeshRenderer>();
    9.        renderer.enabled = false;
    10.  
    11.        // this will wait 2 seconds before turning on
    12.        StartCoroutine(WaitToDisplay(2.0f));
    13. }
    14.  
    15. IEnumerator WaitToDisplay(float seconds)
    16. {
    17.          yield return new WaitForSeconds(seconds);
    18.          Image image = GetComponent<Image>();
    19.          image.enabled = true;
    20. }
    Its slightly more complicated to make something stop and start in the update function but not too tricky:
    Code (CSharp):
    1. public float runTime = 2.0f;  // how long we should run for
    2. public float pauseTime = 2.0f  // how long we should pause for
    3.  
    4. bool paused = false;  // are we paused?
    5. float currentRunTime =0.0f;  // Tracks how long we've been runnning
    6.  
    7. void Update()
    8. {
    9.        if (!paused)
    10.        {
    11.                // Do all you unPaused code here.
    12.                // animating stuff, moving it whatever
    13.                currentRunTime += Time.deltaTime;
    14.                if (currentRunTime >= runTime)
    15.                {
    16.                         paused = true;
    17.                         currentRunTIme = 0.0f;
    18.                         StartCoroutine(DoPause());
    19.                 }
    20.         }
    21. }
    22.  
    23. IEnumerator DoPause()
    24. {
    25.         yield return new WaitForSeconds(pauseTime);
    26.         paused = false;
    27. }
     
    Last edited: Sep 20, 2016
  4. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    Thank you for helping.

    I altered the first set of code to the one below (3D with game objects). It does turn off the game object but it doesn't seem to turn it back on. I tried it with both and without the meshrenderer code. I get this error message: "Coroutine couldn't be started because the the game object 'Sphere' is inactive! UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
    StartDelay:Awake() (at Assets/StartDelay.cs:21"

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class StartDelay : MonoBehaviour
    5. {
    6.  
    7.     void Awake()
    8.     {
    9.         GameObject gameobject = GetComponent<GameObject>();
    10.         gameObject.SetActive(false);
    11.  
    12.         // this turns off the picture
    13.         // if you had a MeshRenderer you could do the same thing:
    14.         // You would only do ONE of these not both. depending on whats
    15.         // on your object
    16.  
    17.         MeshRenderer renderer = GetComponent<MeshRenderer>();
    18.         renderer.enabled = false;
    19.  
    20.         // this will wait 2 seconds before turning on
    21.         StartCoroutine(WaitToDisplay(2.0f));
    22.     }
    23.  
    24.     IEnumerator WaitToDisplay(float seconds)
    25.     {
    26.         yield return new WaitForSeconds(seconds);
    27.         GameObject gameobject = GetComponent<GameObject>();
    28.         gameObject.SetActive(true);
    29.     }
    30. }
    With the other set of code I get a teleporting type of situation where the object disappears every few seconds, but I need it to only stay away at the start for a few seconds and then function as it normally would.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class StartDelay3 : MonoBehaviour
    5. {
    6.     //use inspector for object position, adjust 0,0,0 for direction of object
    7.     public Vector3 pos1 = new Vector3(-4, 0, 0);
    8.     public Vector3 pos2 = new Vector3(4, 0, 0);
    9.     public float speed = 1.0f;
    10.  
    11.  
    12.     public float runTime = 2.0f;  // how long we should run for
    13.     public float pauseTime = 2.0f;  // how long we should pause for
    14.  
    15.  
    16.     bool paused = false;  // are we paused?
    17.     float currentRunTime = 0.0f;  // Tracks how long we've been runnning
    18.  
    19.     void Update()
    20.     {
    21.         if (!paused)
    22.         {
    23.             // Do all you unPaused code here.
    24.             // animating stuff, moving it whatever
    25.             transform.position = Vector3.Lerp(pos1, pos2, (Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f);
    26.  
    27.             currentRunTime += Time.deltaTime;
    28.             if (currentRunTime >= runTime)
    29.             {
    30.                 paused = true;
    31.                 currentRunTime = 0.0f;
    32.                 StartCoroutine(DoPause());
    33.             }
    34.         }
    35.     }
    36.  
    37.     IEnumerator DoPause()
    38.     {
    39.         yield return new WaitForSeconds(pauseTime);
    40.         paused = false;
    41.     }
    42. }
     
    Last edited: Sep 20, 2016
  5. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    You can't turn it back on because I did this:
    Code (CSharp):
    1. Image image = GetComponent<Image>();
    2. image.enabled = false;
    which just turns off the Image script (the part thats displaying the image)
    You did this:
    Code (CSharp):
    1. GameObject gameobject = GetComponent<GameObject>();
    2. gameObject.SetActive(false);
    3.  
    which turns Everything on that game Object off.. including *THIS* script. So once its turned off it can't turn itself back on.
    You have just disable the image drawing portion with .enable = true/false; You can only use SetActive() from a different gameobject if you ever want to turn it back on.
     
  6. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    Ah ok, I see. I thought that Image was for 2D and sprites or something so I turned them into game objects. I get the following error message with Image:

    " Severity Code Description Project File Line Suppression State
    Error CS0246 The type or namespace name 'Image' could not be found (are you missing a using directive or an assembly reference?)"

    What does this mean and how do I solve this?
     
  7. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Image *IS* for 2D sprites, I commented in my original post you would have to change Image to whatever you were using to display your image. Are you using a Mesh and a MeshRenderer? is so you need to use this code:
    Code (CSharp):
    1. MeshRenderer renderer = GetComponent<MeshRenderer>();
    2.         renderer.enabled = false;
    Turning on/off the image your GameObject is displaying will naturally be dependent on exactly what is displaying that image
     
  8. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    Thank you. It works now. Sorry for the misunderstanding.
    Is there a way to have the " StartCoroutine(WaitToDisplay(2.0f)); " visible and adjustable in the inspector? So I can have multiple objects with the same script but with different times of appearance?
     
  9. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Just make a script called StartDelay
    Code (CSharp):
    1. public float DelayTime;
    2. void Awake()
    3. {
    4.        MeshRenderer renderer = GetComponent<MeshRenderer>();
    5.        renderer.enabled = false;
    6.        StartCoroutine(WaitToDisplay(DelayTime));
    7. }
    8. IEnumerator WaitToDisplay(float seconds)
    9. {
    10.          yield return new WaitForSeconds(seconds);
    11.          Image image = GetComponent<Image>();
    12.          image.enabled = true;
    13. }
    Stick that on every GO that needs to be delayed. You can have other scripts on it too. Then change the StartDelay in the editor for how long it should delay before starting
     
  10. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    Again, thank you.

    Before, I changed Image/Meshrenderer to GameObject and that turned the object off completely right? Could I use another object as a spawning system and use this script to have the Objects actually become active at those set delays instead of just showing up / showing the image? Although the script works now it's not quite what I had in mind because the balls move through each other since there is no delay in when they start moving, if that makes sense.

    This is the code that I sort of scrambled together in the process:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SpawnDelay2 : MonoBehaviour
    5. {
    6.     //Sphere can be any object.
    7.     public GameObject Sphere1;
    8.     public GameObject Sphere2;
    9.  
    10.     float timer = 0f;
    11.  
    12.     void Start()
    13.     {
    14.  
    15.         Instantiate(Sphere1, new Vector3(0, 0, 0), Quaternion.identity);
    16.     }
    17.  
    18.  
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.  
    23.         timer += Time.deltaTime;
    24.  
    25.         if (timer >= 2)
    26.         {
    27.             Instantiate(Sphere2, new Vector3(0, 0, 0), Quaternion.identity);
    28.         }
    29.     }
    30.  
    31. }
    but I couldn't get it to work properly and it creates an endless amount of clone objects, whereas I just want only the few objects on a pre set location that I've set in the editor. I just want them to activate with a delay as we've done with the Meshrenderer.
     
    Last edited: Sep 21, 2016
  11. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Make your sphere object with all its scripts + my Delay script.. Then drag it down and make it a prefab. Call it DelaySphere. Don't have any actual spheres in the Scene, Create a Empty GameObject with this script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. public class SpawnDelay2 : MonoBehaviour
    4. {
    5.     // I set it to create 4 objects, change it to what you need
    6.     int numberObjects = 4;
    7.  
    8.     // These variables all need to be assigned in the editor
    9.     public GameObject prefab;
    10.     public Vector3[] positions = new Vector3[numberObjects];
    11.     public StartDelay;  // the delay between each object
    12.     void Start()
    13.     {
    14.         for (int i=0;i<numberObjects;i++)
    15.         {
    16.               GameObject nextObj = Instantiate(Sphere1, new Vector3(0, 0, 0), Quaternion.identity);
    17.                nextObj.transform.position = positions[i];
    18.                DelayScript delayScript = nextObj.GetComponent<DelayScript>();
    19.                delayScript.DelayTime = (i+1)*StartDelay;
    20.         }
    21.     }
    22. }
    The positions variable will be an expandable one, that you can set the positions of all your objects in (x,y,z)
    All your objects will slowly pop in each a set amount apart. If StartDelay =2seconds.. then you will get an object popping in at 2,4,6,8 seconds
     
    PVisser likes this.
  12. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    Thanks. I've made a DelaySphere prefab with scripts attached and an empty 'spawner' object, but for some reason I get all sorts of errors with the above script.

    "Invalid token ';' in class, struct, or interface member declaration - 11 - Active"
    "A field initializer cannot reference the non-static field, method, or property 'SpawnDelay2.numberObjects - 10 - Active"
    "The name 'StartDelay' does not exist in the current context."
    "The name 'Sphere1' does not exist in the current context - 16 - Active"
    "Unexpected symbol `;' in class, struct, or interface member declaration - 11"

    I don't even know how where to even begin how to solve this..
     
    Last edited: Sep 21, 2016
  13. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    You'd have to post the code of script thats giving you errors
    Though I can tell you this error:
    Is because you have a class somewhere called SpawnDelay2. That class is the master blueprint for that class. Your not allowed to just modify or access that class directly. You need to make an instance of it. (Create an object from class). That is basically what your doing when you put a script on a Game Object. However, if you try to access SpawnDelay2 from another script, it will yell at you for trying to mess with the master blueprint you would need something like this:
    Code (CSharp):
    1. SpawnDelay2 script = TheOtherGameObject.GetComponent<SpawnDelay2>();
    2.  
    3. // then we can modify things in spawndelay2 since we have a handle on the instance of spawndelay2 we created
    4. script.numberObjects -10  
    Though you shouldn't have to access SpawnDelay2 from somewhere else.. Its your "controller". You should be using the public variables I posted in the script to let SpawnDelay2 run everything.
     
  14. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    Alright. So this is the DelayScript I have on the DelaySphere (prefab):

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class DelayScript : MonoBehaviour
    5. {
    6.  
    7.  
    8.     public float DelayTime;
    9.     void Awake()
    10.     {
    11.         MeshRenderer renderer = GetComponent<MeshRenderer>();
    12.         renderer.enabled = false;
    13.         StartCoroutine(WaitToDisplay(DelayTime));
    14.     }
    15.     IEnumerator WaitToDisplay(float seconds)
    16.     {
    17.         yield return new WaitForSeconds(seconds);
    18.         MeshRenderer renderer = GetComponent<MeshRenderer>();
    19.         renderer.enabled = true;
    20.     }
    21. }
    And this is the script that I'm having issues with that is for the spawner object:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. public class DelaySpawner : MonoBehaviour
    4. {
    5.     // I set it to create 4 objects, change it to what you need
    6.     int numberObjects = 4;
    7.  
    8.     // These variables all need to be assigned in the editor
    9.     public GameObject prefab;
    10.     public Vector3[] positions = new Vector3[numberObjects];
    11.     public StartDelay;  // the delay between each object
    12.     void Start()
    13.     {
    14.         for (int i = 0; i < numberObjects; i++)
    15.         {
    16.             GameObject nextObj = Instantiate(Sphere1, new Vector3(0, 0, 0), Quaternion.identity);
    17.             nextObj.transform.position = positions[i];
    18.             DelayScript delayScript = nextObj.GetComponent<DelayScript>();
    19.             delayScript.DelayTime = (i + 1) * StartDelay;
    20.         }
    21.     }
    22. }
    23.  
    These are the 2 active scripts (+1 for moving the spheres) but I'm not seeing where, or how, they cause the errors. The issue seems to be the word "StartDelay" and a ; sign that is seen as invalid?
     
    Last edited: Sep 21, 2016
  15. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    small typo I must have made, change:
    Code (CSharp):
    1. public StartDelay;  // the delay between each object
    to:
    Code (CSharp):
    1. public float StartDelay;  // the delay between each object
    Every variable has to have a type.
     
  16. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    That fixed the issue with StartDelay.

    Now these errors are remaining:
    "A field initializer cannot reference the non-static field, method, or property 'DelaySpawner.numberObjects' "
    " Unexpected symbol `;' in class, struct, or interface member declaration "
    "The name 'Sphere1' does not exist in the current context "

    Any ideas about these? I tried to change the name of Sphere 1 to DelaySphere but that doesn't work.
    I can't find any ; signs that are missing or can be removed to fix it.
    And the error about the [numberObjects] does not even make sense to me.