- Home /
Execution Order of Scripts - Awake and OnEnable
I am facing issues related to scripts execution order and this point is out of my mind though I am an experienced, Unity developer. So I expect little bit explanation regarding this.
This is my MenuContoller script code:
public class MainMenuController : MonoBehaviour
{
[SerializeField] Text bestScoreText;
[SerializeField] Toggle soundToggle;
private void OnEnable()
{
Init();
}
private void Init()
{
if (GameManager.Instance == null)
Debug.Log("null game manager");
GameManager.Instance.PlayerLives = 0;
bestScoreText.text = DataStorage.RetrieveBestScore().ToString("D5");
SoundManager.Instance.IsSoundEnabled = DataStorage.RetrieveSoundStatus() == GameConstants.STAT_ON ? true : false;
soundToggle.isOn = !SoundManager.Instance.IsSoundEnabled;
}
}
This is my GameManager script code:
public class GameManager : MonoBehaviour
{
private static GameManager instance;
//
private int levelIndex;
private int gameScore;
private int playerLives;
void Awake()
{
instance = this;
}
public static GameManager Instance
{
get
{
return instance;
}
}
}
I am getting NullReferenceException during execution:
Now I can't able to understand - how the OnEnable method gets executed before other script's Awake method?
Because of this reason, I am getting a null reference exception. As per my understanding, all scripts Awake methods get executed first then after OnEanble call for all scripts of the project.
Please explain to me this point so my side confusion gets solved.
Answer by Bunny83 · Oct 19, 2019 at 04:36 PM
Awake and OnEnabled are essentially called right after one another. They are called directly from the internal object initialization routine. For example if you instantiate a prefab with a script that has an Awake and OnEnabled method like this:
void Awake()
{
Debug.Log("Awake");
}
void OnEnable()
{
Debug.Log("OnEnable");
}
Now consider this Instantiate code:
Instantiate(ourPrefab);
Debug.Log("Instantiated");
This will produce the following order:
"Awake"
"OnEnable"
"Instantiated"
As you can see in the flow chart Awake and OnEnable are both part of the initialization step. So when the object is initialized and it was already enabled in the editor (so it's serialized in it's enabled state) it would first call Awake and immediately after than OnEnable will be called.
You also might want to read the Awake documentation which states:
Each GameObject's Awake is called in a random order between objects. Because of this, you should use Awake to set up references between scripts, and use Start to pass any information back and forth. Awake is always called before any Start functions.
That random order is simple the order in which the objects are initialized. You shouldn't rely on any particular order in this case.
Your main issue is your singleton implementation:
private void Awake()
{
instance = this;
}
For singleton objects that has to pre exist in the scene you should use something like this:
public class SoundManager : MonoBehaviour
{
private static SoundManager instance == null;
public static SoundManager Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<SoundManager >();
if (instance == null)
Debug.LogError("No SoundManager instance found in the scene");
}
return instance;
}
}
// [ ... ]
@Bunny83 thanks for your quick reply :) Let me clear this more - Basically this is a single scene game and on the first run, the null reference exception is showing in the console. So there is no chance of multiple instances of Game$$anonymous$$anager script as per my understanding...
Also, I don't have an issue with Sound$$anonymous$$anager script - I have problem with Game$$anonymous$$anger script, I have edited my question :)
I don't see any difference from the script you posted previously. It's still the same issue. Your "$$anonymous$$ain$$anonymous$$enuController" instance is initialized first while your Game$$anonymous$$anager instance is initialized later. Therefore Awake and OnEnable of your Game$$anonymous$$anager will run before Awake and OnEnable of your $$anonymous$$ain$$anonymous$$enuController. Have you actually read the documentation of Awake and read the section I quoted? Also do you actually understand the difference in the singleton implementation I've posted? The important thing is that the singleton initialization does not depend on the Awake call but is lazy initialized whenever you access the Instance property first.
basically what you should keep in $$anonymous$$d is that the order of these functions for your scene will be like this, assu$$anonymous$$g you have 2 gameobjects both already active the moment you press play. What wil happen is Awake() object 1 -> OnEnable() Object 1 -> then Awake() object 2 -> Onenable() object 2.
. Probably you are assu$$anonymous$$g its awake -> awake -> enable -> enable which is not the case.
Your answer
Follow this Question
Related Questions
A way to know if unity was just opened? [ExecuteInEditMode] 0 Answers
OnEnable not called after all Awake and not all OnDisable before OnDestroy? 1 Answer
Cached references set in awake aren't persisting 0 Answers
OnEnable, Awake, Start order 8 Answers
Should OnEnabled() be changed to be called after Start()? 1 Answer