OnLevelWasLoaded still called from destroyed gameobject

I have a Generic Singleton script so I can tie persistence and instances of certain scripts like PlayerController and GameManager. OnLevelWasLoaded is in the GameManager so I can spawn the player in the correct location depending on the Trigger object they hit in previous scene. The GameManager saves their spawnPoint (location) to the trigger and the spawnName of the trigger object. That trigger will load the scene.

These triggers allow the player to go from scene to scene. If I send the player back to first scene, the original GameManager and PlayerControllers are still in the scene. My generic Singleton Destroys the objects.

The problem is: OnLevelWasLoaded still gets run even though my console shows the GameManager get destroyed before even correct GameManager runs its OnLevelWasLoaded.

The console looks like this after I go back to the first scene:

  • Only one PlayerController is allowed, destroying Constructor
  • Only one GameManager is allowed, destroying GameManager
  • OnLevelWasLoaded
  • spawnName: Alleyway
  • OnLevelWasLoaded
  • spawnName:

As you can see, the destroyed GameManager is not only still doing OnLevelWasLoaded but its even running after the real GameManager. spawnName is blank on the 2nd because the destroyed GameManager doesn’t get the spawnName until a trigger is hit.

Generic Singleton script: GenericSingleton - Pastebin.com

OnLevelWasLoaded part of GameManager:

	void OnLevelWasLoaded() {
		Debug.Log ("OnLevelWasLoaded");
		Debug.Log ("spawnName: " + spawnName);
		foreach(GameObject trigger in GameObject.FindGameObjectsWithTag("SceneTrigger")) {
			if (trigger.name == spawnName) {
				// SceneTriggers will spawn player on its forward vector (blue) by 1, and right vector (red) by the opposite X they entered.
				Vector3 pos = trigger.transform.position + trigger.transform.forward + (trigger.transform.right * -spawnPoint.x);
				PlayerController.Instance.transform.position = pos;
				break;
			}
		}
	}

Your problem is that things like manager scripts must not being placed in game scenes. You should create an empty loading scene which contains your manager objects. This scene should be loaded only once per session.

If you have a singleton class it could load the loading scene additive if the object isn’t loaded yet. That way you can test every scene in the editor without starting via the loading scene.

Something like that:

public class SomeManager : MonoBehaviour
{
    private static SomeManager m_Instance = null;
    public static SomeManager Instance
    {
        get
        {
            if (m_Instance == null)
            {
                m_Instance = FindObjectOfType(typeof(SomeManager)) as SomeManager;
                if (m_Instance == null)
                {
                    Application.LoadLevelAdditive("_LoaderScene");
                    m_Instance = FindObjectOfType(typeof(SomeManager)) as SomeManager;
                }
            }
            return m_Instance;
        }
    }
}

btw: The definition of the singleton pattern actually is that you ensure there’s only one instance. Allowing multiple instances (even when you destroy them as fast as you can) is not a singleton.

edit
NOTE!

Since Unity needs one frame to actually load the “additional level” it’s becomming useless in this case. An alternative is to use a prefab for the singleton:

public class SomeManager : MonoBehaviour
{
    private static SomeManager m_Instance = null;
    public static SomeManager Instance
    {
        get
        {
            if (m_Instance == null)
            {
                m_Instance = FindObjectOfType(typeof(SomeManager)) as SomeManager;
                if (m_Instance == null)
                {
                    SomeManager prefab = Resources.Load("SomeManager", typeof(SomeManager)) as SomeManager;
                    m_Instance = Instantiate(prefab) as SomeManager;
                }
            }
            return m_Instance;
        }
    }
}

Just make sure you have a prefab called “SomeManager” in a resources folder which has the “SomeManager” script attached.

Thank @Bunny83 for the help. This works perfectly. If anyone is wondering how to use this in a Generic Singleton class, here you go:

using UnityEngine;
using System.Collections;

public class Singleton<T> : MonoBehaviour where T : Component {
	[SerializeField]
	bool _persistent = true;

	private static T _instance;
	public static bool IsInstantianted { get { return _instance != null; } }
	protected virtual void Init() {}

	public static T Instance {
		get {
			if (_instance == null) {
				_instance = (T)FindObjectOfType(typeof(T));
				if (_instance == null) {
					T prefab = Resources.Load (typeof(T).Name, typeof(T)) as T;
					_instance = Instantiate(prefab) as T;
					_instance.name = typeof(T).Name; // Removes (clone) naming
				}
			}
			return _instance;
		}
	}

	void Awake() {
		if (Instantiation())
			Init();
	}

	bool Instantiation() {
		if (IsInstantianted) {
			Debug.LogWarning("Only one " + typeof(T) + " is allowed, destroying " + gameObject.name + ".");
			Destroy(gameObject);
			return false;
		}

		_instance = FindObjectOfType(typeof(T)) as T;

		if (_persistent)
			DontDestroyOnLoad(this);
		return true;
	}
}