Does anyone know a website/resource to learn more about yield and coroutines in Unity3D? The online documentation isn’t too much of a help when you are away from Unity itself to test the examples and see the results.
I found several threads on the topic, but they covered very specific problems.
What exactly would you need introduction wise thats not covered in the docs (for example WWW) and a plentitude of resources that contain them?
They just fire off an run async but in the same thread and are used for functions that “need to wait for a result” (polling) like waiting for WWW for example.
No magic behind it or anything complex as they are limited to StartCoroutine → yield for whatever reason and timeframe you need → done
var attackRate : float = 0.5;
private var isAttacking : boolean;
function Update(){
if(Input.GetButtonDown("Fire1") !isAttacking){
StartCoroutine(Attack());
}
}
function Attack(){
isAttacking = true;
animation.CrossFade("attack");
yield WaitForSeconds(animation["attack"].length);
//send damage raycast, instantiate projectile, spawn hit particles
//or whatever here, so they coincide with the end of the attack animation
yield WaitForSeconds(attackRate); //time allowed between attacks
isAttacking = false;
}
No, Update() and Attack() will be running concurrently. You can’t pause Update. The trick in that code is you can only spawn an Attack() coroutine with a mouse click when isAttacking is false, and isAttacking will be true if an Attack() coroutine is running, so multiple clicks won’t spawn more coroutines until the last one is finished.
one important thing about coroutines that is rarely mentioned ( though i think people assume so ) if the game object of the script or the script component itself gets destroyed all coroutines running off it just stop executing.
I often find myself making a game object just for running coroutines that are not tied to any direct object.
Also one thing that i learned too late with c# is if you yield return null it waits a frame. Because i didn’t know this i would often use WaitForEndOfFrame but its not the same. You should only use WaitForEndOfFrame in cases where you need all the scripts in the scene to update prior to the coroutine resuming. The other thing about it is anything that evaluates to null will cause a wait one frame. So say if you had some function that returned a coroutine or yieldinstruction and would return null when it shouldnt wait. You have to check if its null or not before yield returning it unless you want it to wait a frame. The only way functionally to get past this is to make a coroutine from a ienumerator that looks like this:
IEnumerator DoNotWait() { yield break; }
That code will print Test every 10 seconds if someBool is true, or while wait on a function if it’s false. It allows you to pass around YieldInstructions as objects and yield on them regardless of what they are. Useful, I guess for a queue system that will wait a specific time before checking for more work if there is no work to do.
No it is not true!
Unity runs all code you write within a single thread, as such its technically totally impossible to run it concurrently (this includes coroutines which are just asyncronously executed functionality within the same thread) without you explicitely using Threads, which can not access anything that extends from UnityEngine.Object without crashing unity and the player
Yea, what i was saying is even though its not multi threaded and never runs concurently you should not write coroutine code that rely’s on other coroutines or even update functions. You never know what coroutine is going to execute first without a lot of planning and generally you should not have two coroutines setting a value on a member which run at the same time. You do not have to worry about thread safety, but you should be very careful about what your doing within a coroutine in regards to other coroutines or the scripts Update functions.
That is true, although its not concurrent, its not deterministic either so “good guessing” normally gives you one thing and thats “being good fucked up”.
And don’t forget that you can’t debug it either as with any async stuff, at least not in a meaningfull way.
Use the observer pattern and ‘event firing’ when you have dependencies and need multiple things to happen basing on some state or alike changing, never make coroutines wait on ‘status updates’ of other coroutines, you will lose the war, for granted!
EDIT: or just invest in PlayMaker in such a case, thats to design state machines and thats the so far only case I’ve seen where totally unmanageable ‘coroutine dependency chains’ appeared, trying to solve a state machine problem the coroutine bruteforce way.