'function Update' vs 'function Start {while(true)}'?

Found this in the Lerpz Tutorial, in the JetPackParticleController.js.

function Start () 
{
    // Once every frame update particle emission and lights
    while(true)
    {
     ...
     yield;
    }
}

So is it the same as

function Update() {...}

?

As a side: I don't really get what excatly "yield;" does. (I get it's something like stop/wait with what you're doing, but the exact rules are a mystery to me... :/ )

Thanks & Greetz, Ky.

I wouldn't say it's a shortcut: An endless while-loop started in Start() and including a yield should essentially behave very similar as Update(). However, the execution order is very likely a little different. For certain, the first statement in the Start()-construct gets executed before any Update(), so that definitely is a difference.

The best way to find out how exactly the behavior differs would be by experiment:

Have both the Start() method you suggested and an Update() method, putting statements into the log:

function Start() {
    while(true) {
        Debug.Log(string.Format("From Start() - time: {0}", Time.time));
        yield;
    }
}

function Update() {
    Debug.Log(string.Format("From Update() - time: {0}", Time.time));
}

You need the timestamps to find out which Start/Update combinations belong together. The time is set once per frame; in other words: when you call Time.time multiple times in the same frame, it gives you the same result. The next frame, it gives you a different result. So, something like:

From Start()  - time: 3.432
From Update() - time: 3.432
From Start()  - time: 3.623
From Update() - time: 3.623

Would tell you that Start() is called first (which I think to be unlikely), while

From Start()  - time: 3.432
From Update() - time: 3.623
From Start()  - time: 3.623
From Update() - time: 3.842

Would tell you that Update() comes first (more likely).

Regarding yield and CoRoutines: I found it very helpful to look into C# for this (well, that came natural to me as I prefer C# anyways). "yield" in itself doesn't exist in C# - instead, you need "yield return something;" which makes the code more understandable in my opinion (you could do the same in JavaScript, except that you omit the "new"):

yield return new WaitForEndOfFrame(); // waits until after rendering, before displaying
yield return new WaitForFixedUpdate();
yield return new WaitForSeconds(time); // waits the given amount of seconds
yield return 0; // just waits one frame ... well ... great ;-)

Also, in C# you can't just call yield - instead you always need to have it in a "CoRoutine" and the "CoRoutine" must have IEnumerator as return type. And that's the information I needed: An enumerator is basically something that can be called from a loop (like, a game loop, for instance) and return a different result each time it is called (in simplified terms).

In other words: What happens here is that when you have a "yield return something;" in your code, control is returned from your code to the engine. Depending on what you return the engine decides when to retrieve the next "object from the iteration" and when that happens control is returned back to your code. Most likely, Unity keeps a list of all Iterators (in other words: all your CoRoutines) and at a few "hooks" during the main game loop executes those one after the other.

The concept of CoRoutines is quite similar to cooperative multithreading in a single-processor (or single-core) environment: There, each thread has to give up control for other "threads" to get processor time. The main difference from my point of view is that actual multithreading can make use of multiple processors / cores while CoRoutines can't. The nice thing about that is that you don't have to mess with the complexities of concurrent programming and things remain fully predictable and deterministic (which real threads, especially on multi-processor/multi-core machines, are not) ;-)

The construction you see is basically a coroutine, but you're right the ... in above example does about the same as the code in the update. A coroutine can do much more however and is useful for things that happen over a limited amount of time. A coroutine is a function that can suspend execution, using the yield and will go on where it left off after the time specified with the yield (default is next frame, but you can also wait for a number of seconds with WaitForSeconds).

Besides starting a coroutine yourself with StartCoroutine, several functions can act like coroutines just by using a yield somewhere in the code. See again the documentation which functions can or can't be used as a coroutine (I believe basically all the `MonoBehaviour` overridable functions except `Update` and `FixedUpdate`).

In the Unity docs you can find a better explanation and some examples how you can use this.

Thank you, Jashan =)

Out of interest I added the other posibilities I could think of to your script

function Awake()
{
	while(true) 
	{
		Debug.Log("From Awake() - time: " + Time.time);
		yield;
	}
}

function Start() 
{
	while(true) 
	{
		Debug.Log("From Start() - time: " + Time.time);
		yield;
	}
}

function Update() 
{
	Debug.Log("From Update() - time: " + Time.time);
}

function LateUpdate() 
{    
	Debug.Log("From LateUpdate() - time: " + Time.time);
}

function FixedUpdate()
{    
	Debug.Log("From FixedUpdate() - time: " + Time.time);
}

First call is executed in following order:

  • Awake creates an error saying it may not contain a coroutine and thus isn't processed at all.
  • Start
  • FixedUpdate
  • Update
  • LateUpdate

Following calls:

  • FixedUpdate (In my case it was sometimes even called twice or trice before the other functions got called once; but as FixedUpdate isn't framerate-dependend while the other functions are, one will get different results for this depending on the scene one uses this in. So I wouldn't rely on it to get called first. And as FixedUpdate should be used for rigidbodys only anyway, I maybe should have left it out of this experiment altogether)
  • Update
  • Start
  • LateUpdate

So the Start-function with an ever-true while-loop can be used to fit some code between Update and LateUpdate.

Be aware, however, if you use a condition for the while-loop that can become false, the Start-function won't be called anymore, no matter wether the condition becomes true again...

Cheers & Greetz, Ky.