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
1
Question by KarnEdge · Nov 25, 2013 at 09:30 PM · c#destroydontdestroyonloadonlevelwasloaded

OnLevelWasLoaded still called from destroyed gameobject

I have a Generic Singleton script so I can tie persistence and instances of certain scripts like PlayerController and GameManager. OnLevelWasLoaded is in the GameManager so I can spawn the player in the correct location depending on the Trigger object they hit in previous scene. The GameManager saves their spawnPoint (location) to the trigger and the spawnName of the trigger object. That trigger will load the scene.

These triggers allow the player to go from scene to scene. If I send the player back to first scene, the original GameManager and PlayerControllers are still in the scene. My generic Singleton Destroys the objects.

The problem is: OnLevelWasLoaded still gets run even though my console shows the GameManager get destroyed before even correct GameManager runs its OnLevelWasLoaded.

The console looks like this after I go back to the first scene:
- Only one PlayerController is allowed, destroying Constructor
- Only one GameManager is allowed, destroying GameManager
- OnLevelWasLoaded
- spawnName: Alleyway
- OnLevelWasLoaded
- spawnName:

As you can see, the destroyed GameManager is not only still doing OnLevelWasLoaded but its even running after the real GameManager. spawnName is blank on the 2nd because the destroyed GameManager doesn't get the spawnName until a trigger is hit.

Generic Singleton script: http://pastebin.com/CYhp9Nm4

OnLevelWasLoaded part of GameManager:

     void OnLevelWasLoaded() {
         Debug.Log ("OnLevelWasLoaded");
         Debug.Log ("spawnName: " + spawnName);
         foreach(GameObject trigger in GameObject.FindGameObjectsWithTag("SceneTrigger")) {
             if (trigger.name == spawnName) {
                 // SceneTriggers will spawn player on its forward vector (blue) by 1, and right vector (red) by the opposite X they entered.
                 Vector3 pos = trigger.transform.position + trigger.transform.forward + (trigger.transform.right * -spawnPoint.x);
                 PlayerController.Instance.transform.position = pos;
                 break;
             }
         }
     }
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 KarnEdge · Nov 26, 2013 at 12:34 AM 0
Share

I used a debug output in OnDestroy for the Game$$anonymous$$anager. It shows that even though my Singleton destroys the extra Game$$anonymous$$anager before anything runs, the OnDestroy doesn't happen until the end.

Is there any way to make it stop running anything before it gets destroyed?

The only other way I can think of using a presistant singleton Game$$anonymous$$anager and be able to go to any scene I want without duplicates is not having them in the scene and have some kind of script on every single scene that loads the gamemanager if its missing on start. That seems silly to me.

2 Replies

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

Answer by Bunny83 · Nov 26, 2013 at 12:52 AM

Your problem is that things like manager scripts must not being placed in game scenes. You should create an empty loading scene which contains your manager objects. This scene should be loaded only once per session.

If you have a singleton class it could load the loading scene additive if the object isn't loaded yet. That way you can test every scene in the editor without starting via the loading scene.

Something like that:

 public class SomeManager : MonoBehaviour
 {
     private static SomeManager m_Instance = null;
     public static SomeManager Instance
     {
         get
         {
             if (m_Instance == null)
             {
                 m_Instance = FindObjectOfType(typeof(SomeManager)) as SomeManager;
                 if (m_Instance == null)
                 {
                     Application.LoadLevelAdditive("_LoaderScene");
                     m_Instance = FindObjectOfType(typeof(SomeManager)) as SomeManager;
                 }
             }
             return m_Instance;
         }
     }
 }

btw: The definition of the singleton pattern actually is that you ensure there's only one instance. Allowing multiple instances (even when you destroy them as fast as you can) is not a singleton.

edit
NOTE!

Since Unity needs one frame to actually load the "additional level" it's becomming useless in this case. An alternative is to use a prefab for the singleton:

 public class SomeManager : MonoBehaviour
 {
     private static SomeManager m_Instance = null;
     public static SomeManager Instance
     {
         get
         {
             if (m_Instance == null)
             {
                 m_Instance = FindObjectOfType(typeof(SomeManager)) as SomeManager;
                 if (m_Instance == null)
                 {
                     SomeManager prefab = Resources.Load("SomeManager", typeof(SomeManager)) as SomeManager;
                     m_Instance = Instantiate(prefab) as SomeManager;
                 }
             }
             return m_Instance;
         }
     }
 }

Just make sure you have a prefab called "SomeManager" in a resources folder which has the "SomeManager" script attached.

Comment
Add comment · Show 6 · 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 KarnEdge · Nov 26, 2013 at 02:20 AM 0
Share

This seems to make sense. I was trying to look for a way to load the $$anonymous$$anager(s) without having to put them in every scene so I can test each scene. How do you get it to call the _LoaderScene?

I don't seem to have any thing that uses the Game$$anonymous$$anager on awake, start, etc. $$anonymous$$ost of my initializing stuff like cameras are done from the Game$$anonymous$$anager. Should I just make an empty game object for every scene that calls an empty function in Game$$anonymous$$anager just so it creates an instance?

Sorry, these questions may sound dumb but I'm just trying to wrap my head around it all.

avatar image KarnEdge · Nov 26, 2013 at 03:08 AM 0
Share

When I try to Instance Game$$anonymous$$anager from Start(), it gives me a NullReferenceException for it. And when I move the player to the next scene, it now loads OnLevelWasLoaded 5 times in a row which is strange.

EDIT: I Re-imported my project and now it's only doing OnLevelWasLoaded once. Don't know why I had to do that. I still have the NullReferenceException though.

avatar image KarnEdge · Nov 26, 2013 at 04:52 AM 0
Share

I changed my Generic Singleton script with your suggestion and the PlayerController has an Start function to instance the Game$$anonymous$$anager. The only way I was able to get rid of the NullReferenceException was use the LoadLevelAddictive in the Awake of the singleton but it does pull the Game$$anonymous$$anager twice because of that. Fortunately, I catch it and destroy it immediately.

New GenericSingleton: http://pastebin.com/4TnZ10tt

If I can figure out why its doing the NullReferenceException, it will probably fix that issue completely. Then, I'll only need to figure how to Instance the Game$$anonymous$$anager without some empty game object or even the PlayerController.

avatar image KarnEdge · Nov 26, 2013 at 05:06 PM 0
Share

After further testing, it seems that _instance is null throughout the entire Instance method even after the LoadLevelAddictive. It's not able to get the instance until Awake. Apparently this is just how Unity works, the only way to bypass this is by using a Coroutine to do the LoadLevelAddictive and WaitToEndofFrame. Then, it will allow you immediately grab the objects spawned from the _LoaderScene. Unfortunately, I can't figure out how to call a Coroutine from a static singleton. Even doing the coroutine from outside doesn't work.

I've resorted to calling the Game$$anonymous$$anager instance from the Player, and the Instance creates a new GameObject and adds component Game$$anonymous$$anager. This ends up calling the awake automatically and creates the instance.

avatar image Bunny83 · Nov 26, 2013 at 09:07 PM 0
Share

Hmm, it seems like LoadLevelAdditive infact needs one frame to actually load the objects into existance...

Well, that's bad. I actually never tried this approach ;) So thanks for the feedback. Well I guess the only alternative for such a setup might be using a prefab in the resources folder. Those load instantly ;)

I'll add an example to the answer...

Show more comments
avatar image
2

Answer by KarnEdge · Nov 27, 2013 at 02:40 AM

Thank @Bunny83 for the help. This works perfectly. If anyone is wondering how to use this in a Generic Singleton class, here you go:

 using UnityEngine;
 using System.Collections;
 
 public class Singleton<T> : MonoBehaviour where T : Component {
     [SerializeField]
     bool _persistent = true;
 
     private static T _instance;
     public static bool IsInstantianted { get { return _instance != null; } }
     protected virtual void Init() {}
 
     public static T Instance {
         get {
             if (_instance == null) {
                 _instance = (T)FindObjectOfType(typeof(T));
                 if (_instance == null) {
                     T prefab = Resources.Load (typeof(T).Name, typeof(T)) as T;
                     _instance = Instantiate(prefab) as T;
                     _instance.name = typeof(T).Name; // Removes (clone) naming
                 }
             }
             return _instance;
         }
     }
 
     void Awake() {
         if (Instantiation())
             Init();
     }
 
     bool Instantiation() {
         if (IsInstantianted) {
             Debug.LogWarning("Only one " + typeof(T) + " is allowed, destroying " + gameObject.name + ".");
             Destroy(gameObject);
             return false;
         }
 
         _instance = FindObjectOfType(typeof(T)) as T;
 
         if (_persistent)
             DontDestroyOnLoad(this);
         return true;
     }
 }
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

17 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

Related Questions

Execution order of Destroy() and DontDestroyOnLoad() between Scenes 0 Answers

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

How to disable Dont destroy on load 0 Answers

C# override a destroyed GameObject in a List 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