Coroutine working as update, manage duration, and more events in one coroutine
Hello,
private IEnumerator Animating(TBOrbit tbOrbitTarget)
{
yield return new WaitForSeconds(1f);
{
transform.Translate(0, tbOrbitTarget.target.transform.position.y,0);
transform.RotateAround(tbOrbitTarget.target.transform.position, Vector3.up, Time.deltaTime);
}
}
i´m trying to use a coroutine of one second to make some certain actions. During the coding of this one i met a couple of issues that seem not treated anywhere:
1) how can i affect and code the duration of the coroutine? It´s important because it should manage a camera movement in that time.
2) Is there a way to separate different actions in the same coroutine or i am forced to nest the second call yielding at the end of the first?
The code up there is obviously wrong but it´s just a way to show the meaning.
Answer by NoseKills · Sep 15, 2015 at 07:35 PM
@sr3ds A method that returns an iEnumerator and is run in a Coroutine still behaves very much like any other method. The only difference is that you can yield return
to let your program do something else for a while and then get back to running your method from the spot where it last yielded.
If you want any method to do a set of actions repeatedly, you need to do those things for example in a loop. The same thing here. Except that because you can use yielding, you can for example use a while (true) { }
loop as long as you yield inside it so that it doesn't stop the rest of your code from executing for all eternity, like it would in a normal case.
By yield returning different objects that extend "YieldInstruction" (or new WWW() etc.) you can control when the execution of your method continues. For example yield return new WaitForSeconds(1f);
will make the execution continue from this line 1 second after it got there whereas yield return new WaitForEndOfFrame();
will continue execution after all cameras have finished rendering and yield return new WWW(url)
will continue after the WWW request has finished etc.
1) by for example staying in a loop for as long as you want. This will run the loop in the coroutine for 5 seconds and after that the loop terminates and execution flows to the end of the method finishing the coroutine.
IEnumerator MoveCam () {
float startTime = Time.time;
while (Time.time - startTime < 5f)
{
transform.Translate(0, target.transform.position.y,0);
transform.RotateAround(target.transform.position, Vector3.up, Time.fixedDeltaTime);
yield return new WaitForFixedUpdate();
}
}
2) Not sure what you mean exactly. Maybe your understanding of coroutines was just a bit foggy. As said, whatever you do in the method will get executed much like in a normal method. You just have a better control over timing of things.
void Start ()
{
StartCoroutine(DoStuff());
}
IEnumerator DoStuff () {
while (true) {
// do something until we happen to load google.com
System.Object yielder = DownloadOrWait();
// if this is a WWW object, it will automatically yield until the page is loaded
yield return yielder;
if (yielder is WWW) { // that's why it's safe to read it here
Debug.Log(((WWW)yielder).text);
break;
}
}
// after that wait for 2 secs
yield return new WaitForSeconds(2f);
// then move the cam up for 5 secs
float startTime = Time.time;
while (Time.time - startTime < 5f) {
transform.position += Vector3.down * Time.fixedDeltaTime;
yield return new WaitForFixedUpdate();
}
}
private System.Object DownloadOrWait() {
if (Random.Range(0, 2) > 0) {
return new WWW("http://www.google.com");
}
else
{
Vector4 c = Random.insideUnitSphere;
Camera.main.backgroundColor = c;
return new WaitForSeconds(0.5f);
}
}
Nice answer, you cleared me lots of things that i couldn´t get.
So, just to be sure i got it: if i want to link in a chain some different camera movements, i only need to launch a cycle for each movement and separate it with a yield return new WaitForFrame or whatever yield i may need to use?
IEnumerator Linked$$anonymous$$oves()
{
float startTime = Time.time;
while (Time.time - startTime < 5f) {
transform.position += Vector3.down * Time.fixedDeltaTime;
yield return new WaitForFixedUpdate();
}
yield return new WaitForEndOfFrame();
float startTime2 = Time.time;
while (Time.time - startTime2 < 5f) {
//whatever other movement
yield return new WaitForFixedUpdate();
}
and so on.
Thanks anyways. This was brilliant.
If it was helpful, please mark this question as Answered with the Tickmark next to the answer @Sr3ds :)
And yes i think you got the point. You can just yield return null;
inside the loops too. WaitForEndOfFrame() is meant for something specific
Waits until the end of the frame after all cameras and GUI is rendered, just before displaying the frame on screen. You can use it to read the display into a texture, encode it as an image file (see Texture2D.ReadPixels and Texture2D.EncodeToPNG) and send it somewhere.
Ok, this was probably last aspect i needed, thanks for your time and for sharing.
I must have missed the question in your comment so I'll add this: you don't necessarily have to yield in BETWEEN the loops in your method if you have many loops in it. You can safely let the execution run from one loop to the other and yield inside the second loop.
Perfect, this now sounds clearer to me. $$anonymous$$eanwhile i managed to make it work, i'm still fighting with some strange behaviours that i just need to test and discover myself. But the system i had in $$anonymous$$d is properly running as a function. Thanks.
Your answer
Follow this Question
Related Questions
Using Grid-like singletons but have an issue with Coroutines. 2 Answers
MissingReferenceException caused in coroutine 0 Answers
How to keep program linear and synchronous while getting user input? 1 Answer
Click two buttons at the same time 0 Answers
Trying to open/close shutter using SpriteRenderer.size and coroutines 0 Answers