Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
3
Question by Lockstep · Sep 28, 2012 at 01:10 PM · coroutinestopcoroutine

Coroutine does not stop when having a coroutine inside.

Inside of my combat logic for my AI I use coroutines to time the behaviour. Basically I start a random coroutine containing one behaviour, wait, then stop the coroutine and repeat. However the stop coroutine part does not work for one behaviour which has another coroutine inside. This results in stacking those coroutines over time. Thus after a while I get an almost constant stream of bullets.

While i was able to work arround this issue by merging both coroutines I am still curious to find out why my initial approach did not work. I am still learning so every help at improving my comprehension is highly appreciated. Thanks in advance.

The essential parts of my code are the following:

 function Start(){
     Combatlogic();
 }
 function CombatLogic() : IEnumerator{
     while(true){
         if(!sleeping){
             yield ChooseBehaviour(healthRatio);
         }
     yield;
     }
 }
 function ChooseBehaviour(modi : float) : IEnumerator{
     //some code
     }else if (** randomized condition **){
         //Debug.Log("Used Fire");
         StartCoroutine( "executeShootNeedle");
         yield WaitForSeconds(needleFireTime);
         StopCoroutine( "executeShootNeedle");
     } 
 //some more code
 }
 function ShootNeedle() : IEnumerator{
     yield WaitForSeconds(needleAim);
     //attack code
     yield WaitForSeconds( needleDelay);
 }
 function executeShootNeedle() : IEnumerator{
     while(true){
         fireTransform.LookAt(target.position);
         yield ShootNeedle();
     }
 }
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

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by kmeboe · Sep 29, 2012 at 12:19 AM

Actually, I don't think Bunny's answer is quite correct. I've turned your example into the equivalent c#, and have it posted below (hence the need for an answer, with formatting, rather than a comment). You can create a new project and attach this script (as "test.cs") to the main camera, and see the original behavior.

 using UnityEngine; using System.Collections;
 using System.Collections.Generic;
 
 public class test : MonoBehaviour 
 { 
     void Start()
     {
         StartCoroutine(Example());
     }
     
     IEnumerator Example() {
         StartCoroutine("executeShootNeedle");
         yield return new WaitForSeconds(10);
         print("Attempting to stop the coroutine...");
         StopCoroutine("executeShootNeedle");
     }    
     
     IEnumerator ShootNeedle() 
     {
         print ("Aim...");
         yield return new WaitForSeconds(3);
         
         print ("Fire!");
         yield return new WaitForSeconds(1);
     }
     IEnumerator executeShootNeedle()
     {
         while(true){
             print ("Starting firing sequence.");
             yield return StartCoroutine(ShootNeedle());
         }
     }
 }


What's very interesting to note is this: StopCoroutine() is clearly getting called; however, executeShootNeedle() (and therefore ShootNeedle()) continues operating after this. If what Bunny said were true, ShootNeedle() should continue running, but executeShootNeedle() should stop running. As we can see from the logs, this is not the case.

The conclusion is that StopCoroutine() is not functioning at all. According to how I interpret the docs, this is a bug. I wonder what's going on under the covers?

Edit:

In addition, I should also point out that if you simply remove the "yield return StartCoroutine..." call from executeShootNeedle(), the stop works correctly. For example:

     IEnumerator executeShootNeedle()
     {
         while(true){
             print ("Starting firing sequence.");
             yield return new WaitForSeconds(2);
         }
     }

Another Edit: another thing I tried was to add a "yield return 0;" after the call to ShootNeedle(), like so:

     IEnumerator executeShootNeedle()
     {
         while(true){
             print ("Starting firing sequence.");
             yield return StartCoroutine(ShootNeedle());
             yield return 0;
         }
     }

My thinking was that perhaps "yield return StartCoroutine()" didn't give StopCoroutine() a chance to actually stop the coroutine. But even with this addition, StopCoroutine() has no effect on anything.

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 Bunny83 · Sep 29, 2012 at 12:48 AM 0
Share

That's actually really a strange behaviour ;) The StopCoroutine does work, but it only does when the inner coroutine is also stopped... It actually makes no sense...

Test it with those functions:

 IEnumerator Example()
 {
     StartCoroutine("executeShootNeedle");
     yield return new WaitForSeconds(10);
     print("Attempting to stop the coroutine...");
     StopCoroutine("executeShootNeedle");
     yield return new WaitForSeconds(3);
     print("stop ShootNeedle ...");
     StopCoroutine("ShootNeedle");
 }   

 IEnumerator executeShootNeedle()
 {
     while(true)
     {
         print ("Starting firing sequence.");
         yield return StartCoroutine("ShootNeedle");
     }
 }

To be honest, i never use StopCoroutine since i never use StartCoroutine with a string. Stopping a coroutine falls in the same category as goto-statements imo.

Anyway, the behaviour doesn't make any sense at all. Feel free to file a bug report :)

avatar image Lockstep · Sep 29, 2012 at 12:49 AM 0
Share

Thank you for your answer. I tested it again and sent a bugreport to unity.

avatar image kmeboe · Sep 29, 2012 at 01:00 AM 0
Share

Crazy stuff. I probably wasted way too much time researching this. Oh well...I feel like I know more about coroutines now. And maybe Bunny's advice is good: stay away from StopCoroutine, and all is well with the world. :D

Although goto...I have to admit, I love goto in C++. A strategically-placed goto can be great. <puts up fists>

avatar image
1

Answer by Bunny83 · Sep 28, 2012 at 11:52 PM

Sure, each coroutine runs on it's own. When you start a coroutine and yield on this coroutine the calling coroutine just waits for the "nested" coroutine to finish. When you stop the calling coroutine it won't stop the coroutine you started in this coroutine.

The best fix would be to not use a coroutine for ShootNeedle and place the yields in ExecuteShootNeedle:

 function ShootNeedle(){ // Not a coroutine anymore
     //attack code
 }
 function executeShootNeedle() : IEnumerator{
     while(true){
         fireTransform.LookAt(target.position);
         yield WaitForSeconds(needleAim);
         ShootNeedle(); // just call it as normal function
         yield WaitForSeconds( needleDelay);
     }
 }

Stopcoroutine can only halt a coroutine while it's yielding. Keep in mind Unity don't uses threads for the scripting. All your scripts and coroutines are running sequential in the main-thread. Whenever a coroutine yields another coroutine or just the gameloop can continue.

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 Lockstep · Sep 29, 2012 at 12:15 AM 0
Share

Thank you for your answer. I understand that StopCoroutine would not stop the nested coroutine. I wanted the last initiated attack to finish when the executeShootNeedle coroutine stopped. But what exactly do you mean by "Stopcoroutine can only halt a coroutine while it's yielding"? I thought this would be the case when waiting for ShootNeedle to finish.

I also don't know about threads. When I started using unity my program$$anonymous$$g skill were zero. I learned everything from tutorials and the documentations. So unforunately I don't have a deeper understandig of what runs behind the scene. But I am eager to learn more (thats basically the reason I asked this question).

avatar image kmeboe · Sep 29, 2012 at 12:21 AM 0
Share

See below...the mystery continues (imo).

As far as threads go: coroutines do not represent different threads, but rather they are simply a way to delay and/or reorder execution. From what I understand, all code still runs on a single thread (as Bunny said).

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

12 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

Related Questions

If I StopCoroutine("myCoroutine")', will the variable values in myCoroutine be reset? 1 Answer

Can't call StopCoroutine function from another script. 1 Answer

How to force Coroutine to finish 1 Answer

Coroutine problem 0 Answers

NullReference exception after StopCoroutine 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