Unity singleton manager classes

Like always: it depends. I use singletons of both kinds, components attached to GameObject and standalone classes not derived from MonoBehaviour. IMO the overall question is how are instances bound to the lifcycle of scenes, game objects, ... And not to forget sometimes it is more convenient to have a component especially referencing other MonoBehaviour objects is easier and safer.

  1. There are classes that just need to provide some values like for example a config class that needs to load settings from persistence layer when called. I design theese classes as simple singletons.
  2. On the other hand some objects need to know when a scene is started i.e. Start is called or have to perform actions in Update or other methods. Then I implement them as component and attach them to a game object that survives loading new scenes.

I designed component based singletons (type 2) with two parts: a persistent GameObject called Main, which holds all components and a flat singleton (type 1) called MainComponentManager for managing it. Some demo code:

public class MainComponentManger {
    private static MainComponentManger instance;
    public static void CreateInstance () {
        if (instance == null) {
            instance = new MainComponentManger ();
            GameObject go = GameObject.Find ("Main");
            if (go == null) {
                go = new GameObject ("Main");
                instance.main = go;
                // important: make game object persistent:
                Object.DontDestroyOnLoad (go);
            }
            // trigger instantiation of other singletons
            Component c = MenuManager.SharedInstance;
            // ...
        }
    }

    GameObject main;

    public static MainComponentManger SharedInstance {
        get {
            if (instance == null) {
                CreateInstance ();
            }
            return instance;
        }
    }

    public static T AddMainComponent <T> () where T : UnityEngine.Component {
        T t = SharedInstance.main.GetComponent<T> ();
        if (t != null) {
            return t;
        }
        return SharedInstance.main.AddComponent <T> ();
    }

Now other singletons that want to register as Main component just look like:

public class AudioManager : MonoBehaviour {
    private static AudioManager instance = null;
    public static AudioManager SharedInstance {
        get {
            if (instance == null) {
                instance = MainComponentManger.AddMainComponent<AudioManager> ();
            }
            return instance;
        }
    }

If this class is just for accessing global variables then you don't really need a singleton pattern for this, or use a GameObject.

Simply create a class with public static members.

public class Globals
{
    public static int mStatic1 = 0;
    public static float mStatic2 = 0.0f;
    // ....etc
}

The other solutions are fine but overkill if all you need is global access to variables.