Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 Bigproblem01 · Feb 01, 2015 at 07:56 PM · coroutinestopparametersexitstopcoroutine

How to stop coroutine with parameters?

Hi guys,

I needed a repeating code with wait times which would take parameters, so I couldn't use InvokeRepeating and thus used a coroutine with parameters. Here's the code:

     IEnumerator Invisibility (bool _oneShot, float _invisTime, float _visTime, int _pulses)
     {
         for (int i = 0; i < _pulses; i++) 
         {
             while(GetComponent<SpriteRenderer>().color != BckgrdScript.get.BackgroundColor)
             {
                 GetComponent<SpriteRenderer>().color = Color.Lerp(GetComponent<SpriteRenderer>().color, BckgrdScript.get.BackgroundColor, Time.deltaTime * 5);
                 yield return new WaitForEndOfFrame();
             }
             if(_oneShot)
                 yield break;
             else
             {
                 yield return new WaitForSeconds(_invisTime);
                 while(GetComponent<SpriteRenderer>().color != SquareColor)
                 {
                     GetComponent<SpriteRenderer>().color = Color.Lerp(GetComponent<SpriteRenderer>().color, SquareColor, Time.deltaTime * 5);
                     yield return new WaitForEndOfFrame();
                 }
                 yield return new WaitForSeconds(_visTime);
             }
         }
     }

The problem is, I can't stop it. StopCoroutine("string") method doesn't work here and I don't seem to understand how StopCoroutine(IEnumerator routine); works. Do I have to put some bool checking condition on every single line of the coroutine in order to stop it on time?? What's the solution to this?

Thanks

Comment
Add comment · Show 5
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 Imtiaj Ahmed · Feb 01, 2015 at 08:33 PM 0
Share

As you start the coroutine I assume

StartCoroutine (Invisibility (true, 1f,1f,2));

and no "string" used, you can't stop it using

StopCoroutine ("Invisibility");

So, try this-

StopCoroutine (Invisibility);

Note: The Coroutine call is gameobject bound. So the start and stop calling should be on the same gameobject.

avatar image Bigproblem01 Imtiaj Ahmed · Feb 01, 2015 at 10:10 PM 0
Share

StopCoroutine(Invisibility); won't work and will give an error saying that the StopCoroutine method has invalid arguments (which implies it asks for the string). I have Unity 4.6 so I should have the overloaded method but apparently, this is not how it's used

avatar image Imtiaj Ahmed Imtiaj Ahmed · Feb 01, 2015 at 10:33 PM 0
Share

Oh! $$anonymous$$y bad. Just understood the documents that Please note that only StartCoroutine using a string method name can be stopped using StopCoroutine. Sorry for bad answer.

avatar image Imtiaj Ahmed Imtiaj Ahmed · Feb 01, 2015 at 10:45 PM 0
Share

So, only solution is what you have thought, use bool. Just found out example here

Show more comments

3 Replies

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

Answer by Bunny83 · Feb 02, 2015 at 06:57 PM

It is now possible to stop a coroutine by passing an IEnumerator to StopCoroutine. However what most people don't understand is that you have to pass the same instance you passed to StartCoroutine. Like this:

 IEnumerator inst = null;
 
 // start coroutine
 inst = Invisibility (true, 1f,1f,2);
 StartCoroutine(inst);
 
 // stop coroutine
 StopCoroutine(inst);


As far as I remember there's also an overload that takes a Coroutine object. So this should work as well:

 Coroutine inst = null;
 
 // start
 inst = StartCoroutine (Invisibility (true, 1f,1f,2));
 
 // stop
 StopCoroutine(inst);


PS. Writing code on a tablet is a nightmare ^^

Comment
Add comment · Show 8 · 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 tanoshimi · Feb 02, 2015 at 08:09 PM 0
Share

Ah - that's new... What happened to that suggestion button on pages of the documentation that needed updating? :)

avatar image Bigproblem01 · Feb 03, 2015 at 08:56 AM 0
Share

hmm, I've tried that before and now too, I did:

IEnumerator invis = null; invis = Invisibility(false, 1, 1, 5); StartCoroutine(Invisibility(false, 1, 1, 5));

and then StopCoroutine(invis);, but it doesn't work

avatar image Bunny83 · Feb 03, 2015 at 02:42 PM 1
Share

@Bigproblem01: You did not understand what i said. When you call the Invisibility method it returns an IEnumerator object. Each time you call that method a new IEnumerator object will be created. As i said in my answer, you have to use the same object you passed to StartCoroutine when calling StopCoroutine. You might want to take another look at my code.

I did:

  • Invoked Invisibility to get an IEnumerator object

  • stored that object in the inst variable.

  • passed that object to StartCoroutine to start a new coroutine with that IEnumerator

  • Later i pass the same IEnumerator object to StopCoroutine

When you create a new IEnumerator it has no relation to the one created before.

avatar image Bigproblem01 · Feb 04, 2015 at 12:07 AM 0
Share

Sorry, you're right, I started it with parameters ins$$anonymous$$d of with the invis variable. I still prefer the bool solution in this case since I can just plug in the desired parameters on the spot ins$$anonymous$$d of making separate IEnumerator variables everytime I want to call it, but thanks for the explanation nonetheless, knowledge never hurts! much appreciated man!

avatar image Bunny83 · Jun 04, 2015 at 08:21 AM 1
Share

@entity: Well, that's probably because of UnityScript's "automatic" StartCoroutine ^^.

That means this line in UnityScript:

 theCoroutine = myCoroutine() as IEnumerator;

Will actually produce this:

 theCoroutine = StartCoroutine(myCoroutine()) as IEnumerator;

That's because UnityScript automatically wraps the call of a coroutine in StartCoroutine. So you actually get a Coroutine back which you try to as-cast to IEumerator. The as-cast will return "null" if the cast fails (which of course fails) so you don't store the IEnumerator but null.

As far as i know it's not possible in UnityScript to get your hands on the IEnumerator as the compiler always wraps StartCoroutine around it (unless you use StartCoroutine manually.)

Your first example should work like this as well:

  var theCoroutine : Coroutine = null;
  function AFunction()
  {
      theCoroutine = myCoroutine();
      StopCoroutine(theCoroutine);
  }

$$anonymous$$eep in $$anonymous$$d that the implicit StartCoroutine is always executed on the current $$anonymous$$onoBehaviour. It's possible to use StartCoroutine of a different script to run a coroutine on that script instance. Of course if you want to stop it you have to call StopCoroutine on the same script instance. I just mention that since the implicit StartCoroutine hides this fact and can lead to strange results.

Show more comments
avatar image
6

Answer by CalxDesign · Feb 03, 2015 at 10:34 AM

StartCoroutine returns a Coroutine, so just use:

 Coroutine myCoroutine = StartCoroutine(MyIEnumeratorFunction(arg));

Followed by:

 StopCoroutine(myCoroutine);

Does it need to be any more complicated that this?

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 Bigproblem01 · Feb 05, 2015 at 08:36 AM 0
Share

I'm not in a position to try this out right now but does it work with you? I'm asking because they said StopCoroutine("something") only works when you also start it with "something", i.e. StartCoroutine("something")

avatar image gjf · Feb 05, 2015 at 01:24 PM 0
Share

using the string parameter isn't recommended and could lead to strange run-time behaviour if your coroutine name changes - let the compiler throw an error before that happens.

use it as the answer suggests - it'll work.

EDIT: and cache the SpriteRenderer reference in Awake/Start so you don't have to keep doing a GetComponent. it'll be cleaner, and even run faster ;)

avatar image RamanDhiman · Oct 08, 2018 at 12:32 PM 0
Share

Logged in just to upvote this comment.. thanx mate

avatar image EnsenaSoft · Apr 01, 2021 at 01:43 AM 0
Share

Also logged in just to upvote. Worked great!

avatar image
1

Answer by daneislazy · Feb 03, 2015 at 12:10 PM

So I can't add too much regarding using the Coroutine differently but maybe you'd like some constructive criticism regarding the rest of the code? Primarily, it looks like you are using lerp inappropriately. This is likely because the documentation on it is not great and uses Time.time for the third argument which is misleading. And until recently I didn't know any better either. If your goal was to create a specific effect where the color shifted towards the target color quickly at first then slowed down and didn't really get there for a while. Then, Mission Accomplished! But that can cause a bug and it is not a linear effect(lerp). to make it linear, and significantly more controllable, use something like:

 float totalLerpTime = 2f; //is in seconds, duration of transition
 float currentLerpTime = 0f; // need to be reset before/after while loops
 
 currentLerpTime = 0f;
 while(currentLerpTime < totalLerpTime){
 GetComponent<SpriteRenderer>().color = Color.Lerp(SquareColor, BckgrdScript.get.BackgroundColor, (currentLerpTime += Time.deltaTime)/totalLerpTime);
 yield return new WaitForEndOfFrame();
 }

This should give you a more predictable and controllable transition. Also the notable bug with your current method is that systems running at lower frames/second will actually make the transitions faster because there will be fewer lerp calls and the jumps will be larger. Yes, this seems counter intuitive, but I did the math.

If you want a similar effect like you had before you'll need to do some additional manipulation of that last value (maybe get the square root of it as it's passed in Mathf.Pow((currentLerpTime += Time.deltaTime)/totalLerpTime, 0.5f))

Also, it seems that if _oneShot is set to true it breaks out of the Coroutine and stops it from running after the object has become invisible but before it can become visible again. I'm not sure if this is intentional but if not, you would have to call the Coroutine again with say Invisibility(false, 0, 0, 1) to make it visible again.

Anyways, I hope that helps.

Comment
Add comment · Show 5 · 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 Bigproblem01 · Feb 04, 2015 at 08:40 AM 0
Share

Hey @daneislazy, thanks for all the constructive criticism man, I always welcome and embrace it :D

I'll start backwards: _oneShot is intentional, the object needs to go invisible and stay that way.

the fact that on lower fps the transition will be executed faster is not a bug, but the whole point of using Time.deltaTime, since if the machine lagged (or is just slower), there will be more time between the frames and the lerp will have to "catch up" in order to make the transition on time.

You suggestion is actually pretty good, never thought of incrementing the t variable in lerp with each frame and, while not in this case, generally I hated lerp's non-uniformity, so thanks a lot for that hint. The only thing I don't understand is how come you know that the transition will happen in exactly two seconds?

avatar image daneislazy · Feb 04, 2015 at 09:47 AM 1
Share

The two seconds thing is part of how I said the color transition would be more controllable. The Lerp input parameter is supposed to take in a float from 0 to 1. Then it returns a value between the first color and the second based on that float. So if you just give it (currentLerpTime += Time.deltaTime) it will complete the transition in one second. So I divided that by totalLerpTime. So when it returns 1 currentLerpTime is equal to totalLerpTime. Thus it will complete in whatever you set totalLerpTime to.

Also the "slower frames completing faster" bug is because the first color/value passed to the lerp is being constantly updated so later frames will return smaller values even if the deltaTime is the same. example: take 5%(0.05) off of 10,000 you get 9,500, then take 5% off again and you get 9,025. Whereas if you just take 10%(0.1) off of 10,000 you get 9,000. Do that a bunch of times and the 10% will get close to 0 faster. This is similar to a lerp's behavior when the first value is constantly updated and the 'same' small number is passed in for the 0-1 float.

avatar image Bigproblem01 · Feb 04, 2015 at 11:09 PM 0
Share

yeah I guess you're right about the ti$$anonymous$$g, I have to test it tomorrow though.

But how does your solution fix the bug issue? Even if we add Time.deltaTime with each frame, we're still dealing with the same "caught up" increased time values which will still have their say in the miscalculation no?

avatar image daneislazy · Feb 05, 2015 at 06:53 AM 0
Share

It fixes the bug issue because when the lerp is called I'm always passing in the SqaureColor and the Background color, ins$$anonymous$$d of the Current color and the Background color. And I'm slowly increasing the currentLerpTime because (currentLerpTime += Time.deltaTime) will evaluate to the incremented time, like using ++i.

avatar image Bigproblem01 · Feb 05, 2015 at 01:26 PM 0
Share

ah, I guess I was too sleepy to notice that the first argument was the original value and not the current one. I just tried your lerp and it kicks ass man, I'm very thankful!!

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

26 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

Related Questions

How to force Coroutine to finish 1 Answer

Coroutine start and stop 2 Answers

Coroutine problem 0 Answers

What will StopCoroutine exactly do? 2 Answers

StartCoroutine of a child object using String 1 Answer


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