Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Self creating singleton from a prefab?

Discussion in 'Scripting' started by initAndPlay, Jul 21, 2015.

  1. initAndPlay

    initAndPlay

    Joined:
    May 7, 2015
    Posts:
    1
    Howdy y'all! So I know how to instantiate a prefab and I know how to create a self-creating singleton, but how do you create a self-creating singleton from a prefab?

    Here's the scenario:
    I have a prefab with a bunch of game data: references to other prefabs, settings, descriptions, numbers and what not. I would just make an self-creating XML parsing singleton, but I have prefab references that I can't serialize. I also would just drop the prefab in every scene, but it's constantly changing and several scripts use the data in it. I'm trying to decrease the places where that data could get screwed with.

    Any thoughts? Thanks!
     
    Last edited: Jul 21, 2015
  2. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    164
    I also had this question and just in case someone else will come across this topic via google here are results of my experiment: it's practically impossible to implement. Simply because Unity has no idea to which prefab component (the one which will implement singleton logic) is assigned. When you are trying to access instance, you may create object which will be instance of your own implementation... you have no clue what prefabs uses it. If you decide to assign prefab to singleton implementation that means you have to create object from editor and it's no longer prefab =)

    I partially solved the issue by implementing simple CreateIntance method. You pass prefab and transform... this way you just need to assign prefab to what ever component you are using to implement logic and then simply call for example:

    Code (CSharp):
    1.  
    2.   MySingletonPopup.CreateInstance(this.popupPrefab, popupParent.transform);
    3.  
    4.   public static T CreateInstance(T prefab, Transform transform) {
    5.     if (instance == null)
    6.       instance = Instantiate(prefab, transform);
    7.     return instance;
    8.   }
    In case someone has better solution, please update, thanks!
     
  3. Burkard

    Burkard

    Joined:
    Feb 22, 2014
    Posts:
    13
    Pretty necro, but may help someone in the future... I use this approach (you can call the "instance" of the singleton from any script, even if it wasn't instantiated yet):

    SelfInstantiatingSingleton.cs (name it whatever you want)
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class SelfInstantiatingSingleton : MonoBehaviour
    4. {
    5.  
    6.     public static SelfInstantiatingSingleton instance
    7.     {
    8.         get
    9.         {
    10.             if (_instance == null)
    11.             {
    12.                 GameObject gObj = new GameObject();
    13.                 var tipo = typeof(SelfInstantiatingSingleton);
    14.                 gObj.name = "Set name of singleton here";
    15.                 DontDestroyOnLoad(gObj);
    16.                 gObj.AddComponent<SelfInstantiatingSingleton>();
    17.                 _instance = gObj.GetComponent<SelfInstantiatingSingleton>();
    18.             }
    19.             return _instance;
    20.         }
    21.         set
    22.         {
    23.             _instance = value;
    24.         }
    25.     }
    26.  
    27.     protected static SelfInstantiatingSingleton _instance;
    28.  
    29.     public void sayHello()
    30.     {
    31.         Debug.Log("Hi there!");
    32.     }
    33.  
    34.     public void sayGoodbye()
    35.     {
    36.         Debug.Log("Piss off, dude!");
    37.     }
    38.  
    39. }

    To call it from some script, simply use CLASSNAME.instance...

    Caller.cs
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Caller : MonoBehaviour
    4. {
    5.     void Start()
    6.     {
    7.         SelfInstantiatingSingleton.instance.sayHello();
    8.  
    9.         SelfInstantiatingSingleton.instance.sayGoodbye();
    10.     }
    11.  
    12. }
    13.  
    It will never be instantiated twice :)
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,797
    While we're necroing, here's some variations that allow either an empty object, or an object that can load predefined prefab (or ScriptableObject) data off disk and create a singleton out of it.

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, do not put anything into any scene, just access it via .Instance!

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
     
    Shack_Man likes this.
  5. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,930
    Couple notes for this code.
    - you should not have a public
    set
    , it is selfinstantiating, you should not allow the override of it from other places
    - you do not use the
    var tipo = typeof(SelfInstantiatingSingleton);
    it should be removed
    - instead of the two lines of
    Code (CSharp):
    1. gObj.AddComponent<SelfInstantiatingSingleton>();
    2. _instance = gObj.GetComponent<SelfInstantiatingSingleton>();
    you should have simply
    Code (CSharp):
    1. _instance = gObj.AddComponent<SelfInstantiatingSingleton>();
     
    Last edited: Oct 12, 2021