Coroutine or Invoke??

Hi guys,

I’m trying to call a function with parameters after a set time.

I’ve read that if I use WaitForSeconds in a coroutine then no other code will run until that action is complete. The game I’m making is an action game, and it’s this call is one of a few actions at any one time in game. So I can’t stop the entire code just to wait for that one function call.

Is there a way around having the gameplay code effectively pause until a function is called in coroutine, or for a Invoke to have parameters passed through it?

	// A level announcer. Say what you want for how long.. Used in StartGame(), EndGame(), GivePoints(), TakeLife().
	void AnnounceLevel(string SayWhat, float ForHowLong)
	{
		if(announcementCD <= 0)
		{
		GameObject NewAnnouncer = (GameObject)Instantiate(ScriptAnnouncer, new Vector3(0.5f, 0.5f, 10), Quaternion.identity);
		
			NewAnnouncer.GetComponent<GUIAnnouncer>().WhatToSay = SayWhat;
			NewAnnouncer.GetComponent<GUIAnnouncer>().LifeTime = ForHowLong;
			
			announcementCD = ForHowLong;
		}
		else
		{
			Invoke ("AnnounceLevel", announcementCD);
		}
	}

	// Update() called every frame.	
	void Update ()
	{
		if(announcementCD > 0.0f)
		{
			announcementCD -= Time.deltaTime;
		}
	}

I understand I could make a array to store AnnounceLevel’s parameter’s… but that seems a little messy… Is there a better way?

Wait, I suppose you’ve got a misconcept on coroutines there. To make it simple, coroutines are exatcly like any other method call, with the exception of the special ability of halting in the middle and continuing by itself later. The WaitForSeconds will not halt the game for the amount of time specified. It will make the coroutine to return (be yielded) immediately after seeing the WaitForSeconds yield statement. After the specified time passes, the coroutine will automatically be called again and continue from where it has stopped. While the coroutine waits for the time to pass, the game runs normally.

http://unitygems.com/coroutines/

"Summary

  1. Coroutines are a really good way of making a sequence of operations happen over time or when some external process is completed
  2. Coroutines are not threads and are not asynchronous
  3. Nothing else is running when your coroutine is executing
  4. Your coroutine will resume when the conditions of your yield statement are met
  5. Coroutines are inactive when the script is disabled or the object is destroyed
  6. yield return new WaitForSeconds is dependent on game time which is affected by Time.timeScale"

So number 3 is incorrect or misworded?

Neither. As I said, they are like normal methods. If you do an infinite loop there, for example, the game will hang.

However, coroutines uses the yield statements (number 4). What this means is that the coroutine will halt its execution and give the execution flow control back to the calling thread. When they do that, they schedule themselves in the unity player to be called again when the yield statement condition is true. While the condition is false, the coroutine is not executing and your game will be busy executing the normal game flow. As soon as the condition becomes true, the unity player will halt everything when it gets the chance, and resume the coroutine where it has stopped before (the yield statement) - and that’s why they are synchronous.

You can make a simple test: put a cube falling with gravity, and a coroutine called right at the awake method of a script, with a yield return WaitForSeconds(10000). You will see that the cube still falls.

Also, the reference guide entries might help
http://docs.unity3d.com/Documentation/Manual/Coroutines.html
http://docs.unity3d.com/Documentation/ScriptReference/MonoBehaviour.StartCoroutine.html

Best explanation I’ve had on Unity forums. Thanks Kirlim :slight_smile:

Actually… Is this right?

	// A level announcer. Say what you want for how long.. Used in StartGame() and EndGame().
	void AnnounceLevel(string SayWhat, float ForHowLong)
	{
		if(announcementCD <= 0)
		{
		GameObject NewAnnouncer = (GameObject)Instantiate(ScriptAnnouncer, new Vector3(0.5f, 0.5f, 10), Quaternion.identity);
		
			NewAnnouncer.GetComponent<GUIAnnouncer>().WhatToSay = SayWhat;
			NewAnnouncer.GetComponent<GUIAnnouncer>().LifeTime = ForHowLong;
			
			announcementCD = ForHowLong;
		}
		else
		{
			StartCoroutine(PendingAnnouncer(SayWhat, ForHowLong));
		}
	}
	
	IEnumerator PendingAnnouncer(string SayWhat, float ForHowLong)
	{
		yield return new WaitForSeconds(announcementCD);
		{
			GameObject NewAnnouncer = (GameObject)Instantiate(ScriptAnnouncer, new Vector3(0.5f, 0.5f, 10), Quaternion.identity);
		
			NewAnnouncer.GetComponent<GUIAnnouncer>().WhatToSay = SayWhat;
			NewAnnouncer.GetComponent<GUIAnnouncer>().LifeTime = ForHowLong;
			
			announcementCD = ForHowLong;
		}
	}

    // Update() called every frame. 

    void Update ()

    {

        if(announcementCD > 0.0f)

        {

            announcementCD -= Time.deltaTime;

        }

    }

The messages are still coming up on top of each other… I want them to make pending actions if two are called at once…

What exactly are you trying to, theoretically? I think that might be a better starting point for help than trying to iron out your existing code.

To make pending actions you mean to wait the first one to finish, to only then starting the second operation? (e.g if 3 welcome messages are sent at once, the game shows one for 3 seconds, then the next for 3 seconds and finally the last one for another 3 seconds)

If that is the case, you might want to use a Queue. Every announcement request is stored in the queue. You just add requests there. The coroutine or the update method (since the behavior is also possible with a state machine, c# events or a few ‘if’ statements in the Update method) will check if there are requests in the queue when it is idle. If there are, it dequeues one request and show it for the desired time. After the time goes over, it gets idle again and thus will check for new requests. Advantage is that you can queue as much requests as you want without making a confusing methods flux.

Perfect… zombie, Kirlim just described exactly what I’m after :). Okay I didn’t know Unity have a queue thingy… I’m looking at it now. Could you give me a cheeky example of how they work :P.

Thanks guys

The Queue class is from c#:

The namespace is system.collections.generic.

Awesome, I’m from Unrealscript lol. Okay cool, will study.

Thanks man