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
0
Question by zxubian · Dec 08, 2015 at 11:57 AM · c#coroutinessingletonwhile-loop

Coroutine stops after while-loop

I have a singleton LevelManager loading a level, waiting for a script from the newly-loaded level to assign a gameObject to the LevelManager to then do stuff with it.

I have the following code:

 //some gameObject calls the loadLevel coroutine
 void somefunction(sceneToLoad){
     StartCoroutine(LevelManager.Instance.loadLevel (sceneToLoad));
 }
 
 //snippet of LevelManager.cs
 public GameObject levelPrepper = null;
 public IEnumerator loadLevel(string levelName){
     Application.LoadLevel (levelName);
     while (!levelPrepper)
         yield return null;
     yield return StartCoroutine (waitForLevelPrepper());
     print("yay");
     //do stuff
 }
 
 //snippet of the levelPrep.cs:
 void Awake(){
     LevelManager.Instance.levelPrepper = gameobject;
 }

The problem is, "yay" never gets printed. I've done some reading and found that this might happen when the gameObject carrying the coroutine is destroyed. However, LevelManager is definitely never destroyed during the process, so I'm at a loss.

Comment
Add comment · Show 1
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 jctz · Dec 10, 2015 at 02:07 AM 0
Share

How are you sure Level$$anonymous$$anager isn't being destroyed in the process? Are you calling DontDestroyOnLoad() on the gameObject? Have you tried adding a Level$$anonymous$$anager.OnDestroy() and setting a breakpoint? 10/10 times I have a probelm with coroutines being killed, it's due to the owning behaviour being deleted.

1 Reply

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

Answer by OncaLupe · Dec 09, 2015 at 07:59 PM

Does the new level being loaded have a LevelManager that's being destroyed by the singleton? If so are you certain that it's not changing the Instance variable before it does? Remember that Destroy() actually happens at the end of frame, so any code under it is still run.

Also are you sure it's not the waitForLevelPrepper() coroutine that's holding things up? The loadLevel coroutine will wait until it's finished before running the print() line. You can add a print() above that StartCoroutine() to check.

Finally in levelPrep, I'd add a print() to make sure it's actually being run. You're also trying to assign 'gameobject', shouldn't that be 'gameObject'? If it's a variable you made, double check that it's assigned itself.

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 zxubian · Dec 11, 2015 at 07:39 PM 0
Share

Thank you for your reply! I fixed the 'gameobject' bit, I think it came up when I was changing the code before posting here. I did have a bunch of print statements in all of the functions to try and fish out the cause of the issue, Which is how I know that Level$$anonymous$$anager doesn't get destroyed, and that waitForLevelPrepper gets called and finishes according to plan. It turns out that what was causing the issue was that the gameObject that called the coroutine in the first place got destroyed. Apparently, even though the coroutine was from a different gameObject, it still got ter$$anonymous$$ated because the gameObject that initially called it got destroyed, which is a peculiarity I had no idea about and wasn't checking for.

avatar image tanoshimi · Dec 11, 2015 at 08:09 PM 0
Share

I remember getting bitten by that same thing a while back and it taking ages to debug what was going on. Now, as a rule. I never make public coroutines to prevent the risk of them being called by other instances that may get destroyed. Ins$$anonymous$$d I make all my coroutines private and, if necessary, expose a public method that starts them from within the containing class. $$anonymous$$akes it much more easier to trace coroutines as they are running/stopped (which I haven't found any other way of tracing).

avatar image Bunny83 · Dec 12, 2015 at 05:32 AM 0
Share

@zxubian:
Well, you have to understand what a coroutine actually is. A coroutine on it's own is just an object (not a method). You have to distinguish between the actual generator / iterator method which creates the IEnumerator object and Unity's coroutine scheduler which actually "drives" the coroutine.

So this line does two things:

 StartCoroutine(Level$$anonymous$$anager.Instance.loadLevel (sceneToLoad));

It can be split up into this:

 IEnumerator enumerator = Level$$anonymous$$anager.Instance.loadLevel (sceneToLoad);
 this.StartCoroutine(enumerator);

The first line executes the generator method which returns the IEnumerator object that represents the generated statemachine for your coroutine. In the second line you use StartCoroutine on the calling object and hand over the enumerator to Unity's coroutine scheduler. The coroutine will always run on the $$anonymous$$onoBehaviour you called StartCoroutine on. If you want to run the coroutine on the Level$$anonymous$$anager object you can use:

 Level$$anonymous$$anager.Instance.StartCoroutine(enumerator);

However it's usually better to provide a public "start method" for the coroutine inside the Level$$anonymous$$anager object.

 public Coroutine LoadLevel(string aLevel)
 {
      return StartCoroutine( loadLevel( aLevel ) );
 }
 
 private IEnumerator loadLevel(string levelName)
 {
     //...

It's usually a good idea to return the Coroutine object if you want to wait for the coroutine inside another coroutine.

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

6 People are following this question.

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

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

What threads are used in a scene? 1 Answer

How do I make a coroutine from another script stop? 3 Answers

Unity C# Singleton? 6 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