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
0
Question by XoetziX · Apr 10, 2021 at 08:05 PM · editorreferencesingleton

Setting a reference to a Singleton in the editor not possible?

Hello all,

I had a problem with a strange behaviour, just found the reason and want to understand what is going on there.

What I observed in debug mode: My Restard method sets gameHasEnded = false and loads the scene again, but after the reload the value of gameHasEnded was still true.

My setup: A restart button calls the Restart method of my GameManager. This GameManageris a singleton and set to DontDestroyOnLoad. If I call this restart method by the onClick() event of the button (see following screenshot), it does not use the singleton instance of my GameManager.

alt text

I found it out with the following debug logs:

Generating a UUID when the GameManager gets created.

 private void Awake()
 {
         uuid = Guid.NewGuid();
         someCode();
 }

 public void Restart()
 {
     Debug.Log("----------------Restart--------------UUID: " + uuid);
     Debug.Log("----------------Restart--------------UUID: " + GameManager.Instance.uuid);
     GameManager.Instance.gameHasEnded = false;
     gameHasEnded = false;
     SceneManager.LoadScene(SceneManager.GetActiveScene().name);
 }


OUTPUT:

----------------Restart--------------UUID: 00000000-0000-0000-0000-000000000000 ----------------Restart--------------UUID: 87f2267c-65cf-497a-8d5b-d155c711209b

So, when Unity calls the Restart() via the onClick it seems to get somehow a "broken" instance or at least not my singleton. The line "GameManager.Instance.gameHasEnded = false;" solved my problem that the value was not changed in my singelton, but this seems to be an odd workaround.

Can you explain me why it behaves like observed? Is it in general not allow to set a reference to a Singleton in the editor?

1.jpg (8.3 kB)
Comment
Add comment
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

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by AndBje · Apr 10, 2021 at 10:30 PM

There should of course only be one instance of a singleton, hence the name. The problem is that we usually want to add it to the scene's hierarchy and thus a copy of the MonoBehaviour will be created each time the scene is loaded. This can lead to some confusion and the general solution is to check in the Awake() method if there already is a singleton loaded. If there is, we should delete ourselves by calling Destroy().

 public class GameManager : MonoBehaviour
 {
     private static GameManager _instance;
 
     private void Awake()
     {
         if (_instance != null && _instance != this)
         {
             // There is already a singleton loaded. Destroy ourself!
             Destroy(this.gameObject);
             return;
         }
         // We were first, let this object be the singleton! :)
         _instance = this;
         DontDestroyOnLoad(this.gameObject);
     }
     ...



If we follow the principle above we shouldn't add a reference to a public function of the instance, for example from a button. First, it will work as normal. However, when the scene is reloaded, Unity will then again create a new instance of the GameManager and connect it to the button. The second instance will shortly after discover that there already exists an instance and will therefore destroy itself. Nothing will then happen when the user clicks on the button.

If we don't destroy the second copy, as in your case (I assume), the button will still work even after a reload, but it will be connected to the second instance and you have two singletons (and then three, and then four... and so on).

I would recommend you always delete any instance after the first one. So, how should we connect the button to the first instance? Well, we don't. We connect it to a static version.

     public static void Restart()
     {
         _instance.gameHasEnded = false;
         SceneManager.LoadScene(SceneManager.GetActiveScene().name);
     }
 

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 AndBje · Apr 10, 2021 at 10:35 PM 0
Share

There are more advanced ways of doing singletons in Unity (for example https://blog.mzikmund.com/2019/01/a-modern-singleton-in-unity/) but I didn't want to make the example too complicated.

avatar image XoetziX · Apr 11, 2021 at 08:34 AM 0
Share

Thanks @andbje for your reply.

Yes, I indeed use a singleton which destroys any additional (second) instances of this GameManager class in a similar way you showed it.

I assumed that if I set a reference to such a singelton in the editor, that this would also point to my target singleton instance. But I see my mistake in thinking.

However, when the scene is reloaded, Unity will then again create a new instance of the GameManager and connect it to the button. The second instance will shortly after discover that there already exists an instance and will therefore destroy itself.

Yes, okay. The singleton works as it should here. The problem is, that Unity does not use the getter of the singleton class which would return the valid/target instance, right? It creates a new one, which is destroyed then.

So, how should we connect the button to the first instance? Well, we don't. We connect it to a static version.

Ahh, I see. So, in this way I should always get to my single target instance!

Just to avoid dependent problems in the future: Does it have any (negative) side effect to use a static method here?

avatar image AndBje XoetziX · Apr 11, 2021 at 10:58 AM 1
Share

Yes, you are right. Every time Unity loads your scene it will create all game objects in the hierarchy and connect any events to the newly created objects. It does not understand that one of the game objects already exists (the GameManager). The unnecessary copy will itself, in the Awake() method, notice that it was not the first singleton object and destroy itself.

You could of course continue to use the second copy as long as it always uses the static reference _instance (Instance in your code) - but having several copies of a singleton can never be a good idea. So the only solution if you want to call a singleton from Editor code is to call static functions. I can't see that it should create any problems - rather the opposite.

Then we have the never-ending discussion on whether singletons are good or not... but let's not go there... - everything has its place and I don't $$anonymous$$d singletons as long as they are used with care. It would of course be nice if Unity could discover the singleton and reconnect the already existing instance when the scene is loaded.

avatar image XoetziX AndBje · Apr 19, 2021 at 02:45 PM 0
Share

Almost forgot to thank you, so: Thanks for your help! :-)

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

158 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

Related Questions

Reference to Scene Object Component in Prefab Editor, 'Type Mismatch'? 1 Answer

How to have an instance only reference its parent 1 Answer

Reference a script from Editor folder 2 Answers

Parent losing references to Child fields after duplication, copy/paste 0 Answers

Singleton and MonoBehaviour in Editor 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