MonoBehaviors are created using reflection.
This is why the documentation says don’t even bother using the constructor for anything, and instead use ‘Start’ and ‘Awake’ for setting up fields and the sort.
Why is your singleton a MonoBehavior anyway though? It should just be its own type. If you need a gameobject to hook into for things like ‘update’ and the sort, create a gameobject to use as the hook for your singleton.
I’ll give you an example.
I have a Singleton called ‘Game’, game can be accessed from anywhere. In it I have several references, including to my InventoryFactory, the current Players, and my StateManager.
The StateManager is used to hook into some events like Update, and also to set the current player control state. You know, change it from ‘menu control’ to ‘gameplay control’ to ‘paused control’, etc.
In it I create a new GameObject that persists forever (donotdestroy), attach some components to it the uncover the Update function and the sort as C# events, and use this object to attach the state scripts to.
Game Singleton:
using System;
using UnityEngine;
using Ponyo.Items;
using com.spacepuppy;
using com.spacepuppy.Utils;
namespace Ponyo
{
public sealed class Game
{
#region Singleton Interface
private static Game _inst;
public static Game Instance
{
get
{
return _inst;
}
}
/// <summary>
/// If manager singleton has been created yet it creates the manager. It will also load inventory if loadInv is true.
/// </summary>
/// <param name="loadInv">load the inventory pool at creation, otherwise has to be manually loaded</param>
public static void TryInitializeManager(bool loadInv)
{
if (_inst == null)
{
_inst = new Game(loadInv);
}
}
#endregion
#region Fields
private Player _player;
private StateManager _stateManager;
private InventoryFactory _invFact;
private GameObject _mainCam;
#endregion
#region CONSTRUCTOR
private Game(bool loadInv)
{
_player = new Player();
_stateManager = new StateManager();
_invFact = new InventoryFactory();
_stateManager.Update += this.OnUpdate;
if(loadInv)_invFact.Load();
}
#endregion
#region Properties
public Player Player
{
get { return _player; }
}
public StateManager StateManager
{
get { return _stateManager; }
}
public InventoryFactory InventoryFactory
{
get { return _invFact; }
}
public GameObject MainCamera
{
get { return _mainCam; }
}
#endregion
#region LevelStart/LevelEnd
public void LevelStart(GameObject playerAvatar, GameObject mainCam)
{
...
}
public void EndLevel()
{
...
}
#endregion
#region Methods
public void ChangeLevel(string sname)
{
...
}
#endregion
#region Event Handlers
private void OnUpdate(object sender, System.EventArgs e)
{
...
}
}
Here is the StateManager:
using UnityEngine;
namespace com.spacepuppy
{
public class StateManager : System.IDisposable
{
#region Fields
public event System.EventHandler Update;
private GameObject _stateObject;
private UpdateEventHooks _updateHook;
private AbstractState _currentState;
#endregion
#region CONSTRUCTOR
public StateManager()
{
_stateObject = new GameObject("StateObject");
_updateHook = _stateObject.AddComponent<UpdateEventHooks>();
_updateHook.UpdateHook += this.OnUpdate;
UnityEngine.Object.DontDestroyOnLoad(_stateObject);
}
#endregion
#region Properties
public AbstractState Current
{
get { return _currentState; }
}
#endregion
#region Methods
public void GoToNullState()
{
if (_currentState != null) UnityEngine.Object.Destroy(_currentState);
}
public AbstractState GoToState<T>() where T : AbstractState
{
if (_currentState != null _currentState.GetType() == typeof(T)) return _currentState;
AbstractState lastState = _currentState;
if (lastState != null)
{
lastState.OnExitState();
lastState.enabled = false;
}
_currentState = _stateObject.AddComponent<T>();
_currentState.Init(this);
_currentState.OnEnterState(lastState);
if (lastState != null) UnityEngine.Object.Destroy(lastState);
return _currentState;
}
public AbstractState GoToState(System.Type tp)
{
if (!typeof(AbstractState).IsAssignableFrom(tp)) return null;
if (_currentState != null _currentState.GetType() == tp) return _currentState;
AbstractState lastState = _currentState;
if (lastState != null)
{
lastState.OnExitState();
lastState.enabled = false;
}
_currentState = _stateObject.AddComponent(tp) as AbstractState;
_currentState.Init(this);
_currentState.OnEnterState(lastState);
if (lastState != null) UnityEngine.Object.Destroy(lastState);
return _currentState;
}
public AbstractState GoToState(string sStateName)
{
var tp = System.Type.GetType(sStateName);
return GoToState(tp);
}
#endregion
#region Event Hook
private void OnUpdate(object sender, System.EventArgs e)
{
if (this.Update != null) this.Update(this, e);
}
#endregion
#region IDisposable Interface
public void Dispose()
{
UnityEngine.Object.Destroy(_stateObject);
}
#endregion
}
public abstract class AbstractState : MonoBehaviour
{
private StateManager _manager;
public string StateName
{
get { return this.GetType().Name; }
}
public StateManager StateManager
{
get { return _manager; }
}
public void Init(StateManager manager)
{
_manager = manager;
}
public abstract void OnEnterState(AbstractState lastState);
public abstract void OnExitState();
}
}