Enable/Disable Game objects after Wait For seconds

I need to know the best way to enable a game object after “WaitForSeconds”

Here’s a Sample Code in C#

	IEnumerator Start ()
	{
		//Wait for 14 secs.
		yield return new WaitForSeconds (14);

		//Turn My game object that is set to false(off) to True(on).
		GameObject.Find ("MyObject") .SetActive (true);

		//Turn the Game Oject back off after 1 sec.
		yield return new WaitForSeconds (1);

		//Game object will turn off
		GameObject.Find ("MyObject") .SetActive (false);
	}
}

So My problem is, The wait for seconds line of code doesn’t work. The game Object Becomes active on Start without waiting for 14 secs like i want it to do. Same for the Disable portion of the code. What is done wrong here? Can WaitForseconds Be used this way? The Game Object has a script attach that makes a certain thing during the game to happen after the given time

Edit: As mentioned by sysameca

If your game object is disabled it
won’t run the Start() method at all,
not to mention that GameObject.Find()
can’t find any disabled game objects.

In addition to these points, you cannot start a coroutine from an object that is disabled or destroyed, however, you can still start the coroutine on any other Monobehaviour.


Its recommended that you don’t use any FindObject() by string, as it is pretty slow and costly in the long run, so either store it locally within the inspector, which makes it pretty easy to access and use, or add the script straight onto the object.

Now within the start, you can make it start disabled, while leaving it active within the scene, helps with debugging a bit if that’s the way you do it.


Use this script as a manager/container for your coroutines:

public class MyController : MonoBehaviour
{
    
}

Use the script here to disable the object


public class MyObject: MonoBehaviour
{
    public float sec = 14f;
    public MyController MyController;
    void Start()
    {
        MyController.StartCoroutine(LateCall(sec));
    }
 
    IEnumerator LateCall(float seconds)
    {
        if (gameObject.activeInHierarchy)
            gameObject.SetActive(false);
        
        yield return new WaitForSeconds(seconds);
 
        gameObject.SetActive(true);
        //Do Function here...
    }
}

A more advanced implementation would look like this:

public class MyController : MonoBehaviour
{
    private static MyController _instance;

    private void Awake()
    {
        if (_instance == null)
            _instance = this;
    }

    public static void DelayedStart(GameObject target, float time, Action onFinishedCallback)
    {
        _instance.StartCoroutine(DelayedStartCoroutine(target, time, onFinishedCallback));
    }
    private static IEnumerator DelayedStartCoroutine(GameObject target, float time, Action onFinishedCallback)
    {
        if (target.activeInHierarchy) target.SetActive(false);
        
        yield return new WaitForSeconds(time);
 
        target.SetActive(true);
        
        onFinishedCallback?.Invoke();
        //Do Function here...
    }
}

public class MyObject : MonoBehaviour
{
    public float sec = 14f;
    void Start()
    {
        MyController.DelayedStart(gameObject, sec, () =>
        {
            //Do Function Here
        });
    }
}

If your game object is disabled it won’t run the Start() method at all, not to mention that GameObject.Find() can’t find any disabled game objects. The way you can do this is to expose the public GameObject variable in some active game object and from there to activate the disabled one.

public class ActivatorObject : MonoBehaviour
{
    public GameObject objectToActivate;

    private void Start()
    {
        StartCoroutine(ActivationRoutine());
    }

    private IEnumerator ActivationRoutine()
    {        
        //Wait for 14 secs.
        yield return new WaitForSeconds(14);

        //Turn My game object that is set to false(off) to True(on).
        objectToActivate.SetActive(true);

        //Turn the Game Oject back off after 1 sec.
        yield return new WaitForSeconds(1);

        //Game object will turn off
        objectToActivate.SetActive(false);
    }
}

try this:

Don’t make Start as IEnumerator and move all the content to other function.
let’s call the function

functin StartFunction()
{
.....
}

then you need to put on start

StartCoroutine(StartFunction());

i can give you a code example i did for creating shards storm in 1 of my games

int _shardsPerStorm;

//function is called from outside
public void initiateShardStorm()
	{
		StartCoroutine(ShardStorm());
	}

	// shards maker
	IEnumerator ShardStorm() 
	{
		for(int CurrentShardCount=0;CurrentShardCount<_shardsPerStorm;CurrentShardCount++)
		{
			//Debug.Log ("Before Waiting " + _cooldown + " seconds");
			createShard();
			yield return new WaitForSeconds (_cooldown);
			//Debug.Log ("After Waiting " + _cooldown + " Seconds");
		}
	}

void createShard()
{
....
}

Last comment, in terms of resources, ‘Find’ function is extremely expensive and you rather avoid it almost at all cost.
make ‘MyObject’ or an object that can reach ‘MyObject’ accessible from that script.

hope it helps

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {

	public GameObject cubes;// Object to active
	public float sec = 14f;

	void OnTriggerEnter(Collider other)
	{
		if (other.tag == "JetPack") { //tag name Object to Pick Up
			
			cubes.SetActive (true);
			StartCoroutine (LateCall());
		}
	}

	//after same sec Object to false
	IEnumerator LateCall()
	{
		yield return new WaitForSeconds (sec);
		cubes.SetActive (false);
	}

}

easy, use Invoke and specify the time in secs:

Invoke("HideShowGameobject", 5);

create a new method called HideShowGameobject:

void HideShowGameobject()
    {
             if (objectToHide.active)
                   objectToHide.SetActive(false);
             else 
                  objectToHide.SetActive(true);
    }

You can use Invoke in start() to make object active after say 5sec, and then below Coroutine to make object inactive after say 2sec.