Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by DeXoN · Feb 22, 2016 at 01:17 PM · coroutineyield waitforsecondsmanual

Cannot duplicate Coroutines and Yield Instruction in the Unity Manual... Is the manual WRONG?

I cannot seem to get the results as explained in the examples in the Unity Manual http://docs.unity3d.com/Manual/Coroutines.html- particularly the last example with DoCheck() and ProximityCheck().

The Manual says: "Many tasks in a game need to be carried out periodically and the most obvious way to do this is to include them in the Update function. However, this function will typically be called many times per second. When a task doesn’t need to be repeated quite so frequently, you can put it in a coroutine to get an update regularly but not every single frame. An example of this might be an alarm that warns the player if an enemy is nearby."

Here is a simple code that should, according to the manual then, print and advance the variable STEP every 0.1 seconds, however, the output shows that the coroutine and the content of the 'for' loop is actually called every frame, and the value of STEP is not sequentially reduced in the output every 0.1 seconds. Moreover, it appears the routine is duplicated each time it is called to wait, only to be resumed 01s later. This means STEP is 5 at the start, and after STEP reduced from say 4 to 3 at a certain time, STEP then goes back to being 5 (On my machine STEP sequence 5, 4, 3, 3, 5 happened with STEP back to 5 at Time.time = 0.315489s.). This back and forth keeps happening as the old yield calls catch up with more recent ones.

I tried it both in C# and in JS and in neither case can I duplicate what the manual suggests in http://docs.unity3d.com/Manual/Coroutines.html.

Any ideas?

C#:

 public class TestCoroutinesinC : MonoBehaviour {
 
     private bool TEST = false;
     
     void Update () {
     
         if (!TEST) {
             StartCoroutine("TestCoroutine");
         }
 
         if (Time.time >= 0.6) TEST = true;
     }
 
     IEnumerator TestCoroutine() {
 
         for (float STEP = 5; STEP >= 0; STEP -= 1) {
 
             Debug.Log ("The value of  STEP: " + STEP + " at time: " + Time.time);
 
             yield return new WaitForSeconds(0.1f);
 
         }
 
     }
 }


My output: (partial)

The value of f: 5 at time: 0

The value of f: 5 at time: 0.02

The value of f: 5 at time: 0.19133

The value of f: 4 at time: 0.19133

The value of f: 4 at time: 0.19133

The value of f: 5 at time: 0.248696

The value of f: 5 at time: 0.265611

The value of f: 5 at time: 0.282157

The value of f: 5 at time: 0.298827

The value of f: 4 at time: 0.298827

The value of f: 3 at time: 0.298827

The value of f: 3 at time: 0.298827

The value of f: 5 at time: 0.315489

...this output continues on my machine up until...

The value of f: 5 at time: 0.315489

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by GerardQ · Feb 22, 2016 at 01:49 PM

The OP is correct - the manual is confusing and wrong on that page.

maccabe and flashfame: you are both right as well, however you missed the OP's point. He was putting the last example in practice, not the Fade() one. Both your solutions do not apply to that example, because the example is about a function that must be called after each wait, not one that is called only once.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image flashframe · Feb 22, 2016 at 02:01 PM 0
Share

Confusing perhaps, but not wrong.

In the last example, the documentation explains how to use a coroutine to reduce the amount of times you are calling a custom function. They demonstrate the code for the custom function and the coroutine, but they don't show you how to start the coroutine.

To complete their example:

 function ProximityCheck() {
     for (int i = 0; i < enemies.Length; i++) {
         if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance) {
                 return true;
         }
     }
     
     return false;
 }

 IEnumerator DoCheck() {
     for(;;) {
         ProximityCheck;
         yield return new WaitForSeconds(.1f);
     }
 }

 void Update() {
     if (!TEST) {
         StartCoroutine("DoCheck");
         TEST = true;
     }
 }
 

This will start the DoCheck coroutine on the first frame, which will then run until you tell it to stop. The coroutine will yield every 0.1 seconds indefinitely.

avatar image DeXoN flashframe · Feb 22, 2016 at 02:18 PM 0
Share

Yes, flashframe, that is the best explanation. Thank you.

I still feel that the manual is wrong and confusing.

coroutines may be easy to understand for programmers, but in this case leaving out important information in a manual doesn't help.

I think the manual ought to include the Update code that you added, state that a coroutine should only be called once in an update function and also your last sentence: "This will start the DoCheck coroutine on the first frame, which will then run until you tell it to stop. The coroutine will yield every 0.1 seconds indefinitely."

avatar image GerardQ flashframe · Feb 22, 2016 at 02:28 PM 0
Share

The manual didn't say all that, flashframe. Your code and your description may be correct, but none of that is in the manual. I agree with dexon that it is too confusing and the manual is misleading.

avatar image
1

Answer by DeXoN · Feb 22, 2016 at 04:17 PM

Yeah, it's misleading. It neglects to mention pertinent info.

Unless off course the Unity manual is written for people who already know how everything works. As far as I know, that is not the purpose of a manual. It is written for people to look up things that they don't yet understand.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by maccabbe · Feb 22, 2016 at 12:03 PM

Update() is called every frame so your code

 void Update () {
      
          if (!TEST) {
              StartCoroutine("TestCoroutine");
          }
  
          if (Time.time >= 0.6) TEST = true;
      }

is starting a new coroutine every frame for 0.6 seconds.

The code shown in the docs

 void Update () {
     if (Input.GetKeyDown("f")) {
             StartCoroutine("Fade");
     }
 }

only starts a coroutine on the frame when a button is pressed.

I'm guessing you meant to start a new coroutine every 0.6 seconds (not by a coroutine) in which case the following will work

  float time = 0;
  void Update () {   
      time += Time.deltaTime;
      if(time >= 0.6f)
      {
           StartCoroutine("TestCoroutine");
           time -= 0.6f;
      }
  }
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DeXoN · Feb 22, 2016 at 12:46 PM 0
Share

If you do it like you suggest maccabe, then you don't have to use a coroutine just to reduce the frequency of the call. You can call a normal function.

I understand the Input.Get$$anonymous$$eyDown function. That is not the problem. That portion of the example so happens to work because Get$$anonymous$$eyDown returns true only once as a key is pressed.

The problem is the claim of the last section of the manual page about the function DoCheck().

The $$anonymous$$anual says: "$$anonymous$$any tasks in a game need to be carried out periodically and the most obvious way to do this is to include them in the Update function. However, this function will typically be called many times per second. When a task doesn’t need to be repeated quite so frequently, you can put it in a coroutine to get an update regularly but not every single frame. An example of this might be an alarm that warns the player if an enemy is nearby." and then "This would greatly reduce the number of checks carried out without any noticeable effect on gameplay."

That is the functionality that I'm testing.

Clearly that is not the case. I submit that the manual is wrong, that it forgets to mention that it is up to the programmer to ensure the coroutine doesn't get called each update, and that the code in the last manual example should be replaced by, for example:

 public class TestCoroutineinC : $$anonymous$$onoBehaviour {
 
     private bool TEST = false;
 
     private bool IsReadyToDoCoroutine = true;
 
     void Update () {
         
         if (!TEST && IsReadyToDoCoroutine) {
             StartCoroutine("TestCoroutine");
         }
         
         if (Time.time >= 0.6) TEST = true;
     }
     
     IEnumerator TestCoroutine() {
         
         for (;;) {
             IsReadyToDoCoroutine = false;
             Debug.Log ("The value of  STEP:  + STEP +  at time: " + Time.time + " IsReadyToDoCoroutine: " + IsReadyToDoCoroutine);
             yield return new WaitForSeconds(1.0f);
             IsReadyToDoCoroutine = true;
             Debug.Log ("The value of  STEP:  + STEP +  at time: " + Time.time + " IsReadyToDoCoroutine: " + IsReadyToDoCoroutine);
 
         }
         
     }
 }




avatar image flashframe · Feb 22, 2016 at 01:43 PM 0
Share

$$anonymous$$accabe is right. You are starting new coroutines on every frame until "Test" = true.

If you only want your coroutine to run once, then you have to set Test to true immediately after starting it.

          if (!TEST) {
              StartCoroutine("TestCoroutine");
               TEST = true;
          }
  
 



avatar image
0

Answer by JoshuaMcKenzie · Feb 22, 2016 at 03:15 PM

No, the Manual is not wrong, everything supplied its factually correct. Nowhere in the manual does it tell you to create a new coroutine on every frame for 0.6 seconds. Its not the fault of the manual when it doesn't work as expected because it was misued. This all sounds to me like any line from Weird Al's "I'll Sue Ya". The intent of the page was to teach you on the possible uses of coroutines, not delve deep into writing coroutines properly (as that's a broad topic)

try this, Start can be a coroutine and you're having Monobehavior manage that for you:

     public class Test : MonoBehaviour
     {
         IEnumerator Start() 
         {
             for (float step= 5; step>= 0; step--)
             {
                 Debug.Log ("The value of  STEP: " + step + " at time: " + Time.time);
                 yield return new WaitForSeconds(0.1f);
             }
         }
     }

does the code work as expected? and its strikingly similar to what you wrote, the main difference here is how the coroutine is getting invoked

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image GerardQ · Feb 22, 2016 at 04:31 PM 0
Share

Joshua, your code is correct, but in this case I do agree with the OP that the manual is too vague on the subject matter. Even if it is 'factually correct, it won't be helpful to someone who is learning if it is this incomplete. This manual page makes sense to those of us who already understand coroutines. Based on all the confusion that I've seen about coroutines and how people interpret the manual, I think the manual is what is lacking to be honest.

avatar image DeXoN · Feb 22, 2016 at 04:42 PM 0
Share

The manual section is Scripting ---> Scripting overview --> Coroutines.

Not "Scripting --> Scripting Overview -> The possible uses of Coroutines for people who are already expects in writing coroutines."

avatar image GerardQ · Feb 22, 2016 at 04:44 PM 0
Share

Lol. Very true, dexon!

avatar image DeXoN · Feb 22, 2016 at 04:47 PM 0
Share

Thank you GerardQ, maccabbe, flashrider, Joshua$$anonymous$$c$$anonymous$$enzie for taking time to look at this and explain.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

37 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

coroutine not running after yield new WaitForSeconds 1 Answer

Lerping blinks 1 Answer

Coroutine Will NOT Start 3 Answers

Coroutoutine doesnt work properly. 3 Answers

Coroutines /WaitForSecond ain't working 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges