- Home /
[Question] Can someone explain why I get NullReference @ Start() but not during Awake()
Thanks for popping in to help me with this question. Even, though I fixed my code last night I still do not know why it is doing the things it does.
I have 2 scripts and both are attached to the same gameObject called GameController. My initial thoughts were to set the reference to _controller during the Start(), naturally. However, I keep getting a nullReferenceException when I try to access it later during the Load function, however it works fine if I put the reference in Awake() or if I try to reference just before I need to use it. Maybe this has something to do with my DontDestroyOnLoad during my Awake() on GameControllerScript???
Example1: INSIDE SettingsFile.cs......Does not work, returns a nullReferenceException when I later try to reference _controller in the Load() function
void Start()
{
_settingsScript = linkToSettingsMenu.GetComponent<SpecificMenuSettings>();
_controller = gameObject.GetComponent<GameControllerScript>();
}
I set the variable _controller here under Start() , but when I try to access _controller later on during the Load Function it says that (_controller) is the NullReference. Trying to print _controller just before using it does not print anything.
Example2: INSIDE SettingsFile.cs......Settings the reference under Awake() for some reason works though. And I can successfully reference _controller later in the Load() function without problems
private void Awake()
{
_controller = gameObject.GetComponent<GameControllerScript>();
}
// Use this for initialization
void Start()
{
_settingsScript = linkToSettingsMenu.GetComponent<SpecificMenuSettings>();
}
Grabbing the reference in the Awake function seems to work. And when I finally access _controller under the Load Function it works perfectly fine and does not give any nullReference problems.
Example3: INSIDE SettingsFile.cs... It also works if I reference what _controller is, just before I need it (Line16)
public void Load()
{
//make sure the file exists FIRST, before I attempt to read it
if (File.Exists(Application.persistentDataPath + "/settingsInfo.dat"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/settingsInfo.dat", FileMode.Open);
// need a container to pull this info out
// when deserialize we create some generic object, but non-specific
// so we need to cast it to the specific object ( CLASS of GameSettings ) and tell it that is what type it is
cloneGameSettings = (GameControllerScript.GameSettings)bf.Deserialize(file);
// After LOADING we set all of the settings into the GameController
_controller = gameObject.GetComponent<GameControllerScript>();
_controller._gameSettings = cloneGameSettings; //nullRefrenceException is no longer thrown
// then update all the MENUS to reflect this new load
UpdateSettingsMenuWithLoadedValues();
file.Close();
}
}
Example4: INSIDE SettingsFile.cs........... it also will work if I define _controller as a public GameControllerScript monobehaviorClass. And then drag the GameControllerScript manually onto this variable inside SettingsFile.cs..... This also works...
SettingsFile.cs
//public GameObject linkToGameController;
public GameObject linkToSettingsMenu;
public GameObject linkToSound;
public GameObject linkToVolume;
public GameObject linkToAmbientOcclusion;
public GameObject linkToMSAA;
public GameObject linkToPlayer1;
public GameObject linkToPlayer2;
public GameObject linkToPlayer3;
public GameObject linkToPlayer4;
public GameControllerScript _controller;
public GameControllerScript.GameSettings cloneGameSettings;
public SpecificMenuSettings _settingsScript;
private void Awake()
{
}
// Use this for initialization
void Start()
{
_settingsScript = linkToSettingsMenu.GetComponent<SpecificMenuSettings>();
_controller = gameObject.GetComponent<GameControllerScript>();
}
public void Load()
{
//make sure the file exists FIRST, before I attempt to read it
if (File.Exists(Application.persistentDataPath + "/settingsInfo.dat"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/settingsInfo.dat", FileMode.Open);
// need a container to pull this info out
// when deserialize we create some generic object, but non-specific
// so we need to cast it to the specific object ( CLASS of GameSettings ) and tell it that is what type it is
cloneGameSettings = (GameControllerScript.GameSettings)bf.Deserialize(file);
// After LOADING we set all of the settings into the GameController
_controller._gameSettings = cloneGameSettings; //nullRefrenceException is no longer thrown
// then update all the MENUS to reflect this new load
UpdateSettingsMenuWithLoadedValues();
file.Close();
}
GameControllerScript.cs
//Initialization of variables and Classes
public class GameControllerScript : MonoBehaviour {
[System.Serializable]
public class LocalPeopleLoggingIntoTheGame
{
[System.Serializable]
public class LocalPlayers // now we have a bunch of players
{
public string character;
}
public LocalPlayers localPlayers;
}
public LocalPeopleLoggingIntoTheGame localPeopleLoggingIntoTheGame = new LocalPeopleLoggingIntoTheGame();
//Because Gameconroller is in every scene...
//it should contains all the load data and settings stuff
[System.Serializable]
public class SavedPlayerData
{
// ** So basically, inside SavedPlayer Data
//** is a list of player names
//** and inside each of theseListClasses :::
//** they have a list of characterNames(class)
//** which contain things like name, and other data associated with this individual Character
[System.Serializable]
public class TotalArrayOfPlayerNames
{
public string playerName;
[System.Serializable]
public class TotalArrayOfCharacterNames
{
//
// DATA ASSOCIATED WITH THIS INDIVIDUAL CHARACTER
//
public string characterName;
}
public List<TotalArrayOfCharacterNames> arrayOfCharacters = new List<TotalArrayOfCharacterNames>();
}
public List<TotalArrayOfPlayerNames> arrayOfPlayers = new List<TotalArrayOfPlayerNames>();
}
public SavedPlayerData playerData;
[System.Serializable]
public class GameSettings _gameSettings;
public static GameControllerScript control;
private void Awake()
{
if (control == null)
{
DontDestroyOnLoad(gameObject);
control = this;
} else if (control != this)
{
Destroy(gameObject);
}
}
Answer by Glurth · Dec 16, 2017 at 05:38 PM
Since the gameobject reference linkToSettingsMenu
is not initialized, if a value has not been assigned in the editor, it will be equal to null, during start.
Since it is a serialized public variable, and user adjustable in the editor, there is always the possibility the user has deleted the reference, leaving it a null value. In this situation, you should always check, to confirm the value is not null before using it.
if(linkToSettingsMenu!=null)
_settingsScript = linkToSettingsMenu.GetComponent<SpecificMenuSettings>();
else
Debug.Log("linkToSettingsMenu value is null. You probabaly need to assign a gameobject to this variable in the insprector.");
The reason the gameObject
member always works, is becuase it references the GameObject that this component is attached to. So if the script is running, we know gameObject
is never going to be null.
Also important to mention is that even if you ensure your gameobject is not null, this does not mean it necessarily has the component you request is actually attached to it. If this is the case, GetComponent will return null. So, I would suggest an ANOTHER check for null, during start, that displays a message when the specified game object does NOT have the attached component that it should. e.g.
_settingsScript = linkToSettingsMenu.GetComponent<SpecificMenuSettings>();
if(_settngScript==null)
Debug.log("Problem: the object " +linkToSettingsMenu.name + " does not have the expected SpecificMenuSettings component attached.");
Thanks for the reply,
We are referring to _controller , as the variable throwing the null reference exception. NOT linkToSettings ( which is set in the editor), or _settingScript, which has not yet had any problems.
When I access the variable _controller ( a monobehavior class attached to this same gameObject ). I get a null reference Exception only when the reference is SET during the Start function... However, Setting it during the Awake function... or setting it (just before I need to use it) works perfectly fine..
Why is this?
To ask again..... why does this piece of code:
_controller = gameObject.GetComponent<GameControllerScript>();
Why does that code throw a NullReferenceException when I try to access _controller during the my Load function (already posted in the original post)? However, it only throws a null reference exception when I initialize _controller during the Start(). If I Initialize _controller during the Awake() or just before i need to use it in the actual Load() then it works perfectly fine. [Please see previously posted Examples 1-3] I am trying to understand why Start() keeps giving a null reference exception.
There is no obvious reason I can see for this. I would use a set of Debug.Log() commands, as shown in the answer, to attempt to deter$$anonymous$$e why. Avoid making assumptions. For example, check if the _controller variable is ending up null in start. If so try displaying ALL the components attached to the object (using GetComponents() ) It's possible that through the component exists during awake, for some reason we can't see here, it has been removed by the time we get to Start(). The other advantage is you can confirm Start() is ACTUALLY being called. (never used DontDestroyOnLoad, but [perhaps this is preventing start from running when you expect.)
Which does lead to the final question then.... I obviously misunderstand when Awake, Start runs...
Well, it looks like I understand this issue better..... I have re-posted the documentation related to another thread below for future reference.....
Awake is used to initialize any variables or game state before the game starts. Awake is called only once during the lifetime of the script instance. Awake is called after all objects are initialized so you can safely speak to other objects or query them using eg. GameObject.FindWithTag. 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. This allows you to order initialization of scripts. Awake can not act as a coroutine.
http://unity3d.com/support/documentation/ScriptReference/$$anonymous$$onoBehaviour.Awake.html
LOL, I feel like a dummy now. As a new programmer I think I easily forgot the usage definition for start and awake. Oh well, at least I know the reason behind the problem ins$$anonymous$$d of just finding a work around.
Answer by Nikaas · Dec 16, 2017 at 07:30 PM
If Load() is called from some Start() method then _controller may or may not return null when _controller is assigned in a Start() method.
You don't know the order of Start() methods between different MonoBehaviours. Actually you can control that order in the Unity options, but IMO in the long run you will get yourself into bigger trouble by doing that. The thing you know for sure is that all Awake() methods are run first and only when ALL OF THEM are done all The Start() methods are run. That probably is the cause why assigning _controller in Awake() is fine.
Thanks for the comment. After digging into my code to find the order of events happening I realized I was improperly utilizing Start(), as seen in my code for initializing references of [self]. When, according to Unity documentation and best practices. This should always been done in Awake().
Unfortunately it took me more than a day to realize this mistake in my understanding. I guess as a novice programmer it was easy to forget the defintions and usage for both Start() and Awake(). I already found the solution was to _reference in the Awake but couldn't figure out why that worked. Anyways, thanks again.
I have reposted a master Jedi's comment from another thread regarding this (billy4184) The way I see it is really simple. Use Awake() for initiating ONLY this component, and Start() for communicating between components before the game starts. That makes sure all components are ready before they communicate, and you have Start() free to do all your world-building and preparation.
Your answer
![](https://koobas.hobune.stream/wayback/20220612144709im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Logical Error In Spawn Counter (Javascript) 2 Answers
JUMP LOGIC 2 Answers
Really Confused about Scripting Rotations 2 Answers
Please explain Quaternions! 7 Answers
sound registry 0 Answers