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. Join us on Thursday, June 8, for a Q&A with Unity's Content Pipeline group here on the forum, and on the Unity Discord, and discuss topics around Content Build, Import Workflows, Asset Database, and Addressables!
    Dismiss Notice

Use to Singleton

Discussion in 'Scripting' started by omermertguner, Sep 6, 2022.

  1. omermertguner

    omermertguner

    Joined:
    May 21, 2022
    Posts:
    4
    hello everyone. I have 3 different scripts. Let's call them the 1st, 2nd and 3rd. I need to access the data in the 3rd script from the 1st script through the 2nd script and the 2nd script should be a singleton. how can I do it. I would be very happy if you can help.
     
  2. Franco_Voisard

    Franco_Voisard

    Joined:
    Apr 30, 2018
    Posts:
    20
    Hello, mmm... If I don't misunderstood anything... Something like that could do the trick.


    Code (CSharp):
    1. public class FirstScript
    2. {
    3.     private readonly ThirdScript _thirdScript;
    4.  
    5.     public FirstScript(ThirdScript thirdScript)
    6.     {
    7.         _thirdScript = thirdScript;
    8.     }
    9.  
    10.     private void MethodUsingThirdScript()
    11.     {
    12.         Debug.Log(_thirdScript.SomeIntProperty);
    13.     }
    14. }
    15.  
    16. public class SecondScript
    17. {
    18.     public static SecondScript Instance;
    19.     private readonly ThirdScript _thirdScript;
    20.     public SecondScript(ThirdScript thirdScriptReference)
    21.     {
    22.         _thirdScript = thirdScriptReference;
    23.         Instance = this;
    24.     }
    25.    
    26.     private void MethodUsingThirdScript()
    27.     {
    28.         Debug.Log(_thirdScript.SomeIntProperty);
    29.     }
    30. }
    31.  
    32. public class ThirdScript
    33. {
    34.     public int SomeIntProperty;
    35. }
     
    mopthrow likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    33,683
    I like this pattern: 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. }
    There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.
     
    mopthrow likes this.
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    2,757
    It matters whether your scripts are MonoBehaviour or not. @Franco_Voisard's script is pure C# and if you want a MonoBehaviour singleton, check out Kurt's answer. But basically, when you want this kind of behavior with MonoBehaviours you must be mindful of the object's initialization states, because their execution order is now in Unity's hands.

    For this check out the Script Execution Order in settings. For example your singletons are probably "the eldest" of the objects, in terms of importance, because it's likely the other objects will refer to them for some services. They should have a priority (i.e. their Script Execution Order should be lower than default).

    This is just a heads up, if you ever stumble upon this problem.
     
    Franco_Voisard and mopthrow like this.
  5. Franco_Voisard

    Franco_Voisard

    Joined:
    Apr 30, 2018
    Posts:
    20
    When coding in Unity, a common mistake is to make every script as a MonoBehaviour. Often is better (To take advantage from constructors, dependency injection or avoid depending on the Unity lifecycle) using the "Humble Object" pattern, basically you encapsulate a common C# class inside a MonoBehaviour (This way you can take advantage of both things, Unity lifecycle and plain C# advantages)
     
  6. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    918
    Humble Object is an interesting pattern, I agree - but it's pretty advanced stuff, and pretty out of the norm, so I would not personally recommend it for somebody who's still getting to grips with the basics (also dependency injection, and even assigning to class members in the constructor are possible to pull off with MonoBehaviours as well... but that's getting off-topic :D).

    Singleton is a simple, functional pattern to use starting off, but at least at some point I would recommend also looking into the service locator pattern. It has some benefits compared to the singleton pattern, such as being able to retrieve instances by an interface they implement.
    Code (CSharp):
    1. using System;
    2. using System.Linq;
    3. using UnityEngine;
    4. using Object = UnityEngine.Object;
    5.  
    6. public static class Get
    7. {
    8.     public static IPlayer Player => GetOrCreate<Player>();
    9.     // TODO: Add more service getters here...
    10.  
    11.     private static T GetOrCreate<T>() where T : class
    12.     {
    13.         var instance = Cached<T>.instance;
    14.         if(instance is null)
    15.         {
    16.             if(typeof(Component).IsAssignableFrom(typeof(T)))
    17.             {
    18.                 instance = (T)(object)Object.FindObjectsOfType(typeof(T)).Single();
    19.             }
    20.             else
    21.             {
    22.                 instance = Activator.CreateInstance<T>();
    23.             }
    24.  
    25.             Cached<T>.instance = instance;
    26.         }
    27.  
    28.         return instance;
    29.     }
    30.  
    31.     private static class Cached<T> where T : class
    32.     {
    33.         public static T instance;
    34.     }
    35. }
    Usage:
    Code (CSharp):
    1. public class First : MonoBehaviour
    2. {
    3.     public void Example()
    4.     {
    5.         Second second = Get.Second;
    6.         Third third = second.Third;
    7.     }
    8. }
     
    orionsyndrome likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    33,683
    And while we're at it, let's not forget the time-honored process of just putting a bunch of shared data into a ScriptableObject instance and dragging it into everything that needs it.

    https://docs.unity3d.com/Manual/class-ScriptableObject.html

    Doesn't even need to have any predefined data... you can just make it all runtime data, mark everything as
    [NonSerialized]
    and get on with your game.
     
  8. Gamadrila

    Gamadrila

    Joined:
    Sep 5, 2021
    Posts:
    142
    It is possible to copy data from the first script to the second one.