I finished exporting the beta version of my first game, but have run into a few bugs with the exported build which did not occur in the Editor.
Main issue at hand: In the game, I have a crow that circles over the moving scarecrow enemy, but in the build the crow is just staying in its original position and doesn’t do anything. Reading an exported .txt copy of the Console Log from the build, I was able to determine that in the Awake function, one of the other controller scripts I reference is returning as null in the build for some reason, which is why the script is disabling after that point and not doing anything. Here’s the code that’s breaking:
if (gameObject.name == "Crow1") scarecrowControllerOB = GameObject.FindWithTag("Enemy/Scarecrow1");
else if (gameObject.name == "Crow2") scarecrowControllerOB = GameObject.FindWithTag("Enemy/Scarecrow2");
else if (gameObject.name == "Crow3") scarecrowControllerOB = GameObject.FindWithTag("Enemy/Scarecrow3");
else if (gameObject.name == "Crow4") scarecrowControllerOB = GameObject.FindWithTag("Enemy/Scarecrow4");
print(System.DateTime.Now.ToLongTimeString() + " : " + "Crow Controller: Parent Scarecrow Located");
if (scarecrowControllerOB == null) print(System.DateTime.Now.ToLongTimeString() + " : " + "Crow Controller: Scarecrow controller Object = null");
scarecrowController = scarecrowControllerOB.GetComponent<ScarecrowController>();
print(System.DateTime.Now.ToLongTimeString() + " : " + "Crow Controller: Scarecrow controller script defined");
if (scarecrowController == null) print(System.DateTime.Now.ToLongTimeString() + " : " + "Crow Controller: Scarecrow controller script = null");
//THIS IS WHERE THE SCRIPT BREAKS, AND RETURNS A NULL REFERENCE EXCEPTION
isDying = scarecrowController.isDying;
print(System.DateTime.Now.ToLongTimeString() + " : " + "Crow Controller: Is Dying Bool defined");
So I’ve identified the problem…but I’m not sure why the ScarecrowController script is returning as null in the build, but not in the editor - or, more importantly, how to fix that?
Some of the most common reasons for this are:
- order of script execution might be different in build and you have a dependency
- you have some other bug that prevents this field from being initialized in time
Congratulations on completing Step #1 of the three-step list… now move onto Step #2!
Step #2 is for you to find HOW it is supposed to be initialized and why it is apparently NOT being initialized before you try to use it.
Debugging can be invaluable for Step 2.
By debugging you can find out exactly what your program is doing so you can fix it.
Use the above techniques to get the information you need in order to reason about what the problem is.
You can also use Debug.Log(...);
statements to find out if any of your code is even running. Don’t assume it is.
Once you understand what the problem is, you may begin to reason about a solution to the problem.
Remember with Unity the code is only a tiny fraction of the problem space. Everything asset- and scene- wise must also be set up correctly to match the associated code and its assumptions.
And for completeness and future browsers of this thread, the three steps:
The answer is always the same… ALWAYS!
How to fix a NullReferenceException error
Three steps to success:
- Identify what is null ← any other action taken before this step is WASTED TIME
- Identify why it is null
- Fix that
NullReference is the single most common error while programming. Fixing it is always the same.
Some notes on how to fix a NullReferenceException error in Unity3D:
http://plbm.com/?p=221
- order of script execution might be different in build and you have a dependency
* you have some other bug that prevents this field from being initialized in time
I did try and switch the Crow Controller’s Awake() function to Start(), to see if it was an order of execution issue, and got the same error, so I don’t think that’s the problem in this instance.
This is how it’s setup in Unity:
The Scarecrow and Crow controllers are both children of the Scarecrow1 game object. I used the debug log to confirm that the Crow Controller script is successfully locating the SC1Controller game object, so it’s the GetComponent which appears to be breaking. I also confirmed that the ScarecrowController script is executing its Awake() before the CrowController script’s Awake() - also, the ScarecrowController script is working on the scarecrow itself.
Ended up just making the ScarecrowController variable public and assigning it in the inspector instead of using GetComponent, and that did the trick!
No surprise at all… I even have a standard blurb about it!!
Happy you’re back in service!
Keep in mind that using GetComponent() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.
Here’s the bare minimum of stuff you absolutely MUST keep track of if you insist on using these crazy Ninja methods:
- what you’re looking for:
→ one particular thing?
→ many things?
- where it might be located (what GameObject?)
- where the Get/Find command will look:
→ on one GameObject? Which one? Do you have a reference to it?
→ on every GameObject?
→ on a subset of GameObjects?
- what criteria must be met for something to be found (enabled, named, etc.)
- if your code expects one instance and later you have many (intentional or accidental), does it handle it?
If you are missing knowledge about even ONE of the things above, your call is likely to FAIL.
This sort of coding is to be avoided at all costs unless you know exactly what you are doing.
Botched attempts at using Get- and Find- are responsible for more crashes than useful code, IMNSHO.
If you run into an issue with any of these calls, start with the documentation to understand why.
There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.
In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.
It is ALWAYS better to go The Unity Way™ and make dedicated public fields and drag in the references you want.
1 Like