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
2
Question by FredMastro · Oct 12, 2019 at 09:51 PM · gameobjectbuttonclickdontdestroyonload

DontDestory gameobject doesn't work on button click after a new scene loads

Hi guys,

I have Scene 1 where I load a GameManager script into a GameObject. It's a singleton and set to DontDestory when it loads.

If I go to Scene 2 and pull in the GameObject, I set the On Click to a function for that button. This works if I load directly into Scene 2.

The problem is when I go back to Scene 1 and load and click a button that loads Scene 2, the button on Scene has lost it's reference to the GameObject even though it's under Don't Destroy.

Any thoughts?

Elaborating:

In the Editor: I open Scene 1 and I have a button that references a gameObject "Game Manager", which itself has a script called GameManager.cs. In the script I have a method to play audio and load scene 2. In the script I also have a method to load Scene 1.

Still in the Editor: I open Scene 2 and I have another gameObject "Game Manager" with has the same script. I have a button in the scene that calls the other method in the Game Manager. Works fine if I just load each scene independently.

When I play the game: Scene 1 loads, the button click works fine and loads Scene 2, but Scene 2 the button has lost it's link to the Game Manager object.

GameManager inherits a Singleton class that make sure there's only one and marks it DontDestory

 public class GameManager : Singleton<GameManager>
 {
 
     public AudioClip ButtonClickAudio;
     public bool NewGame;
     public AudioSource GameSFXSource;
 
     // Start is called before the first frame update
     void Start()
     {
         GameSFXSource.clip = null;
     }
 
     // Update is called once per frame
     void Update()
     {
         
     }
 
    public void LoadPoliceDesk()
     {
         SceneManager.LoadScene("PoliceDesk");
     }
 
     public void LoadMainMenu()
     {
         SceneManager.LoadScene("MainMenu");
     }
 
     public void NewOrContinue()
     {
         if (NewGame)
         {
             NewGame = false;
             PlayButtonClick();
             SceneManager.LoadScene("StoryIntro");
             
         }
         else
         {
             LoadPoliceDesk();
         }
     }
 
     public void PlayButtonClick()
     {
         GameSFXSource.clip = ButtonClickAudio;
         GameSFXSource.Play();
     }


Singleton.cs using UnityEngine;

 //<T> can be any Type
 public class Singleton<T> : MonoBehaviour where T : Component
 {
 
     //The instance is accessible only by the getter
     private static T _instance;
     
     public static T Instance
     {
         get
         {
             if(_instance == null)
             {
                 Debug.Log("Looking for existing instnace of " + typeof(T).Name + " in memory to return");
                 //Making sure there not other instances of same type in Memory
                 _instance = FindObjectOfType<T>();
 
                 if(_instance == null)
                 {
                     Debug.Log("Instance not found.. creating instnace of " + typeof(T).Name + " in memory");
                     GameObject obj = new GameObject();
                     obj.name = typeof(T).Name;
                     _instance = obj.AddComponent<T>();
                 }
 
             }
 
             return _instance;
         }
     }
 
     //Virtual Awake() can be overridden
 
     public virtual void Awake()
     {
         if(_instance == null)
         {
             //If null, then this instance is now the singleton of the assigned type
             _instance = this as T;
 
             //making sure this instance is kept persisted across screens
             DontDestroyOnLoad(this.gameObject);
         }
         else
         {
             Debug.Log("Imposter of " + typeof(T).Name + " found. Destroying! pew pew pew.. boom!");
             //Destroy the imposter!
             Destroy(gameObject);
         }
     }
 }


I've had some more luck if I make the GameObject with the GameManager script a pre-fab. I can get it to work that way to go back to Scene 1, but then the buttons don't work anymore. It's very odd.

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 ivaylo5ev · Oct 12, 2019 at 11:26 PM 0
Share

I edited my answer with a solution.

2 Replies

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

Answer by GrayLightGames · Oct 13, 2019 at 04:15 AM

Hi @FredMastro, I believe the following is happening: your scene 2 button is linked to your scene 2 GameManager, which because of the singleton implementation, is destroyed. So it's expected that the linkage on the button would be lost. Unity does not relink everything to your singleton instance. You'd like the button to reference the scene 1 GameManager which is being carried into scene 2, yes? You'd need to do something like repoint the button to the GameManager instance. One easy-to-implement option would be to have the button reference a controller or other GameObject that is not singleton, but have that object refresh its link to the GameManager instance when the scene loads. So your button would call IntermediateController.GameManagerFunction(), which would just in turn call the intended function on the GameManager instance. Since the controller would refresh its linkage to the scene 1 GameManager, you'd be good to go. If that doesn't make sense, reply and I'll try to clarify.

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 FredMastro · Oct 13, 2019 at 04:22 PM 0
Share

Ahh, that makes sense @GrayLightGames . I would have the intermediateController call the Game$$anonymous$$anager instance function directly.

avatar image GrayLightGames FredMastro · Oct 13, 2019 at 06:59 PM 0
Share

Great, glad I could help. Good luck with your project!

avatar image ihave1000usernamesnow · May 29, 2020 at 01:08 AM 0
Share

Thanks GrayLightGames, this was a simple solution to the problem I was having too.

avatar image
1

Answer by ivaylo5ev · Oct 13, 2019 at 06:59 AM

Allright, Here is the cause. Your singleton has the following logic working:

  1. When the singleton object is loaded on a scene, it checks if it is the only instance in the awake method.

  2. If it is so, then the current object is set as the singleton instance and that instance will be used in your code.

  3. If there is already an instance, then the singleton code will destroy what points to "this" in the Awake method, in order to leave the other instance alive.


Now, back to your setup. Lets look at Scene 1. It has some game object with your singleton component in place, we will refer it to as "Scene 1' Singleton". You have a field on a button pointing to the game object that owns "Scene 1 Singleton", and that link is established in the editor.

On Scene 2 you have another game object with the singleton component. You have a button in Scene 2 which has a click handler, linking to the owner game object of the "Scene 2' Singleton".

Both scenes will work perfectly when launched independently.

Now what happens when you hit play: you load Scene 1 (for example). "Scene 1 Singleton" checks if it is the only instance, and since it indeed is, remains alive. Your button will work as expected. You press the button and it loads Scene 2. By that time, "Scene 1 Singleton" is already set as "Don't destroy on load" and will be preserved. As scene 2 loads, "Scene 1 Singleton" will be alive and well. But, Scene 2 has another game object -- remember "Scene 2' Singleton". Right now, as the scene loads, its Awake method is called and it checks if it is the only instance. It will say it is not, since it will see "Scene 1' Singleton" is there. So it will be destroyed instead (see step 3 from the beginning of my post). This will leave the Scene 2's button to be associated with null instead of what Scene 2' Singleton once was, and clicking the button will fail.

I hope this explains the behavior you observe. But I believe you also need a solution.

I assume that your singleton game object is different game object than the one having the button. In that case, you need to do the following:

  • Create a custom component which has the following code (Replace Click1 and Click2 with your click handler methods):

            public class GameManagerProxy: MonoBehaviour
         {
               public void Click1()
               {
                     GameManager.Instance.Click1();
               }
               public void Click2()
               {
                     GameManager.Instance.Click2();
               }
         }
    
    

Then, in both scene 1 and scene 2, you add GameManagerProxy to the component which has the button (any component which is different than the singleton game object will be OK). In your button point to the proxy component instead of the singleton and select the appropriate click handler.

  • Do the same for Scene 2

This will make sure both scenes are calling the existing singleton object.

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 FredMastro · Oct 13, 2019 at 04:24 PM 1
Share

Thanks, yes @ivaylo5ev , this backs up what @GrayLightGames, that intermediate object to call the original's instance. Thank you both.

I couldn't reward you both, I split the reward though.

avatar image ivaylo5ev FredMastro · Oct 14, 2019 at 05:19 PM 0
Share

No worries, I hope you get the clear picture of the situation. Singletons in unity are hard to manage and not very pretty to use in general, they stray a lot from the original Singleton design pattern. The good of situations like this is is that you'll hopefully get better understanding for the lifecycle of the unity game objects and scene transitions. I'd be glad if I helped.

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

191 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 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 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 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 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 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 avatar image avatar image avatar image avatar image avatar image

Related Questions

Animator Not Playing on Button Click 0 Answers

On Button Click Enable - Disable GameObject Through Inspector 1 Answer

How to make 3D object become the cursor? 2 Answers

Best Button for UnityGame 2D 1 Answer

how would i create a button that animates the main camera when clicked? 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