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 Addyarb · Sep 25, 2015 at 10:10 PM · waitforsecondsienumerator

IEnumerator Stalling Or Stopping

Hi Community!

[Question Solved: See answer comments for demonstrated solution]

I'm truly stumped by this issue. When I supply my IEnumerator yield's WaitForSeconds parameter with 0.1f-0.9f, it works fine. However, when I supply it with an int from another script, hangs up on the WaitForSeconds bit, and just doesn't move past that line of code. I have Debugged and found that it is getting an int (1) as a parameter. Interestingly, if I hard-code the value of 1 into the WaitForSeconds parameter, it does the same thing.

Here's my code:

     public IEnumerator Slow(int projLevel) //Accept the level of the projectile as parameter
     {
         if (slowed) yield break; //If we're already slowed, break out
         slowed = true; //Let the script know we're slowed
         enemy.speed /= projLevel+1; //Slow down this enemy
         yield return new WaitForSeconds(projLevel); //Wait for supplied time (this is where it stops)
         enemy.speed *= projLevel+1; //Speed up our enemy to normal speed
         slowed = false; //Let the script know we're no longer slowed
     }


Comment
Add comment · Show 6
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 Addyarb · Sep 27, 2015 at 07:56 AM 0
Share

Still haven't found my issue with this. I tried reformatting my IEnumerator to eli$$anonymous$$ate the yield break; portion since I figured I might be breaking out somehow, but still - none of the characters get past line 5.

avatar image Bunny83 · Sep 27, 2015 at 09:05 AM 1
Share

Are you sure that you don't stop the coroutine somewhere? Coroutines are stopped / aborted whenever:

  • you call StopAllCoroutines on the monobehaviour that runs the coroutine.

  • you call StopCoroutine with a valid handle to that coroutine.

  • the object that runs the coroutine is disabled or destroyed.

So who's starting the coroutine and on which object is the coroutine running?

avatar image Rostam24 · Sep 27, 2015 at 09:17 AM 0
Share

Try WaitForSeconds(projLevel * 1.0f) to confirm the issue has to do with int or float, and not something else.

avatar image Addyarb · Sep 27, 2015 at 10:23 PM 0
Share

@Bunny83 Thanks for the reply! So there are two components to this. It looks like this:

  1. Projectile is launched with a projectile script component attached

  2. Projectile hits enemy

  3. Enemy detects OnTriggerEnter and reads the type of projectile via boolean on the projectile script (slow, freeze, ignite, damage, etc.)

  4. Enemy starts his/her own coroutine (IEnumerator Slow, for example) based on the data received.

  5. Of course - if the enemy is below 1 health it destroys itself.

The projectile does destroy itself 1 second after hitting the enemy - so perhaps there's a reference lost there? It doesn't make sense that that lost reference would halt a coroutine on another gameObject (the enemy) though.

@Rostam24 I've tried static typecasting, and a number of different solutions including multiplying by a float - and they all give the same result. They only get past the yield if they are less than 1 second. :/ Thanks for the input though!

avatar image Runalotski Addyarb · Sep 28, 2015 at 12:09 AM 0
Share

from what i see waitForSeconds(float) has no overloaded functions so I dont htink it accepts int you could try

 float waitTime = projLevel;
 
 yield return new waitForSeconds(waitTime);


you could test this by hard coding a 1f into it as a 1 is an int but 1f is a float

avatar image Addyarb Runalotski · Sep 28, 2015 at 01:13 AM 0
Share

I actually set my parameter projLevel to a float ins$$anonymous$$d of an int in the method parameter - so even if it didn't accept an int, it would be implicitly converted before it was stored (unless I am fundamentally wrong in unboxing theory here).

In other words:

 public IEnumerator Slow(float projLevel) //Accept the level of the projectile as parameter

But also, even if WaitForSeconds didn't accept an int as an argument, wouldn't I get a console error and not just a complete abortion of the enumeration?

2 Replies

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

Answer by Bunny83 · Sep 28, 2015 at 01:10 AM

Are you sure you start the coroutine on the enemy and not the bullet which might get destroyed the next moment? It doesn't depend where the IEnumerator method is defined. It only matters which StartCoroutine method you used to start the coroutine. StartCoroutine is a method of the MonoBehaviour class. The coroutine runs on the MonoBehaviour instance on which you use StartCoroutine.

So without more details about your actual setup we can't help you any further.

@Runalotski @Rostam24:
The data type "int" can be implicitly converted to "float", so that's not a problem here.

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 Addyarb · Sep 28, 2015 at 01:28 AM 0
Share

Thanks @Bunny83. It appears you got to it a full 60 seconds before @Bored$$anonymous$$ormon, but you both supplied the same information. I incorrectly assumed that the caller of the coroutine was arbitrary and that the actual coroutine lived inside the same script as the IEnumerator was located - but it appears it actually lives inside the caller. Strange and counter-intuitive if you ask me, but I guess that's just one of those things :)

Thanks for the help!

avatar image Kiwasi Addyarb · Sep 28, 2015 at 01:34 AM 0
Share

Its actually normal and useful behaviour once you think about it for a while. You just have to get used to the idea.

avatar image Addyarb · Sep 28, 2015 at 01:43 AM 0
Share

For some instances perhaps. The reason I ran into this issue in the first place was that I was trying to eli$$anonymous$$ate unnecessary lines of code - which this stipulation seems to discourage. Are there specific advantages to having to write a whole new method just to start a coroutine and not worry about disposing of the caller? Seems like you're having to think backwards ins$$anonymous$$d of forwards as far as code flow. Perhaps a question for the forums I'll admit - but if there's a simple answer lay it on me :P

avatar image Bunny83 Addyarb · Sep 28, 2015 at 02:19 AM 1
Share

A lot people get the wrong picture of what a coroutine actually is. First of all it's not a method, it's an object and the actual "coroutine method" just creates that object which implements the IEnumerator interface. Unity now has implemented a scheduler which can "iterate" those objects. You have to pass the object to StartCoroutine which will store the reference to the object internally so the scheduler can actually run / iterate the "object".

You can even declare coroutines in non $$anonymous$$onoBehaviour classes, but to start a coroutine you have to use StartCoroutine which is a method of $$anonymous$$onoBehaviour.

You can run a coroutine on an arbitrary $$anonymous$$onoBehaviour as long as you have a reference to it.

Example:

 public class SomeBehaviour : $$anonymous$$onoBehaviour
 {
     public IEnumerator $$anonymous$$yCoroutine()
     {
         yield return null;
         Debug.Log("done");
     }
 }
 
 public class SomeOtherClass : $$anonymous$$onoBehaviour
 {
     public SomeBehaviour other;
     void Start()
     {
         // this will run the coroutine on this monoBehaviour since we use "this.StartCoroutine("
         StartCoroutine(other.$$anonymous$$yCoroutine());
         
         // this will run the coroutine on the "other" monobehaviour
         other.StartCoroutine(other.$$anonymous$$yCoroutine());
     }
 }

If you want to start a coroutine of another class and have that coroutine run on that class as well, it's easier to provide a calling method that starts the coroutine.

 public class SomeBehaviour : $$anonymous$$onoBehaviour
 {
     private IEnumerator $$anonymous$$yCoroutine()
     {
         yield return null;
         Debug.Log("done");
     }
     public Start$$anonymous$$yCoroutine()
     {
         StartCoroutine($$anonymous$$yCoroutine());
     }
 }
 
 // [...]
 other.Start$$anonymous$$yCoroutine()

avatar image Addyarb · Sep 28, 2015 at 02:01 AM 0
Share

To those who may come across this issue:

Here is what my code looked like before:


Script 1 (Projectile That Gets Destroyed At Arbitrary Time)

 Script2 s2 = TheTargetWeCollidedWith.GetComponent<Script2>();
 StartCoroutine(s2.ExampleCoroutine(ExampleInt));

Script 2 (Target that houses the IEnumerator)

 IEnumerator ExampleCoroutine(int SecondsToWait){
 yield return new WaitForSeconds(SecondsToWait);
 }



Here is what my code looked like after (Corrected):

Script 1 (Projectile That Gets Destroyed At Arbitrary Time)

 Script2 s2 = TheTargetWeCollidedWith.GetComponent<Script2>();
    s2.Call$$anonymous$$ethodToCallCoroutine(ExampleInt());

Script 2 (Target that houses the IEnumerator)

 public void Call$$anonymous$$ethodToCallCoroutine(int waitTime){
 StartCoroutine(Wait(waitTime));
 }    
 
 
 IEnumerator Wait(int SecondsToWait){
     yield return new WaitForSeconds(SecondsToWait);
     }

avatar image
1

Answer by Kiwasi · Sep 28, 2015 at 01:11 AM

A coroutine stops when the MonoBehaviour that calls StartCoroutine is destroyed. So if your call to StartCoroutine comes from the bullet script, you will stop the coroutine running on the other object when the bullet is destroyed.

Solve this by calling StartCoroutine on the target Component. Either by implementing a wrapper method, or by calling someOtherMonobehaviour.StartCoroutine().

To emphasise: It does not matter where the IEnumerator is located. It matters where StartCoroutine is called.

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

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

31 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

Related Questions

fps calculation with while loop in coroutine 2 Answers

Instantiate an object as soon as another object is destroyed 2 Answers

Enable collider then disable it after a certain amount of time 1 Answer

yield return new WaitForSeconds () not working 1 Answer

IEnumerator manipulates variable in android build 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