0
\$\begingroup\$

Given the code:

[CreateAssetMenu(fileName = "newGameManagerInstance", menuName = "Game/Game Manager Instance")]
public class GameManagerSO : ScriptableObject
{
    private GameManager instance;

    public GameManager Instance { get { return instance; } set { instance = value; } }

    private void Awake()
    {
        Debug.Log("1");
    }

    private void OnEnable()
    {
        Debug.Log("2");
    }

    private void OnDisable()
    {
        Debug.Log("3");
    }

    private void OnDestroy()
    {
        Debug.Log("4");
    }
}

I have two questions:

  1. Why the output in console when I enter play mode is "3" and then "2"? Shouldn't OnDisable be executed after OnEnable?

  2. I'm using this scriptable object to hold an object reference only (I don't have the need to serialize the object, it's just a handy way I found to pass that reference through scenes without committing to singletons); can I code all initialization code for the object in OnEnable method? Can I assume it will always execute before any MonoBehaviour read it?

Also

\$\endgroup\$
2
  • \$\begingroup\$ @D.Kallan The reference text you quoted is for MonoBehaviour. My question is about ScriptableObject. \$\endgroup\$ – underthevoid Jan 8 at 13:37
  • \$\begingroup\$ Completely right, sorry. I deleted my comments to not bother others, The documentation on ScriptableObjects feels almost the same yet also feels like a C+P (I'm talking about that line indicating a OnDisable is called followed by OnEnable). docs.unity3d.com/ScriptReference/… \$\endgroup\$ – D.Kallan Jan 8 at 14:16
3
\$\begingroup\$

A ScriptableObject's Awake and OnEnable methods are called (in that order) as soon as the object is loaded.

This occurs when...

  • Loading a scene that contains a reference to the object (including in the editor)

  • Reloading recently referenced ScriptableObjects after a code change

  • Clicking on the object in the Project window or reference selector widget

That means if you're testing a scene that contains a reference to this ScriptableObject, it's already enabled before you click the Play Mode button.

To match the event flow you observe in a built game, Unity starts-up the object from scratch when entering Play Mode. (Imagine you were using your Awake or OnEnable method to generate a random seed for a roguelike's procedural dungeon generation - if it didn't do this, you'd always get the same dungeon when testing in the editor)

But since the object was already started-up, in order to re-start it we have to shut it down first. That means calling OnDisable on it.

So the order of events you see when entering play mode is OnDisable -> Awake -> OnEnable, but only because we've narrowed our view too far. If we step back and look at the wider timeline we'll see something like this:

  1. Launch Unity editor and open scene

    Awake -> OnEnable

  2. Enter Play Mode

    -> OnDisable -> Awake -> OnEnable

  3. Load a different scene that does not reference this object

    -> OnDisable

So it is true that OnDisable occurs after OnEnable. Specifically, the OnDisable in (2) occurs after the OnEnable in (1), just like the OnDisable in (3) follows the OnEnable in (2).

Can I code all initialization code for the object in the OnEnable method? Can I assume it will always execute before any MonoBehaviour can read it?

Yes. That is exactly the purpose of these methods.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.