I’m pretty new to Unity I’ve been working through a series of tutorials on YouTube for creating a hex map. I just worked through the second part - found here
and I can’t get all the code to work - despite going through the video numerous times to see if I’ve missed anything.
The author of the video had to backtrack about a quarter of the way into the video and I think he forgot to explain something that happened during that time…
I’ll paste in the code below. The problem code are the two lines that start with hexGO.GetComponent() - I get an error that says ‘NullReferenceException: Object reference not set to an instance of an object’
Any suggestions would be greatly appreciated!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HexMap : MonoBehaviour {
// Use this for initialization
void Start () {
GenerateMap();
}
public GameObject HexPrefab;
public Material[] HexMaterials;
public readonly int numRows = 20;
public readonly int numColumns = 40;
public void GenerateMap()
{
for (int column = 0; column < numColumns; column++)
{
for (int row = 0; row < numRows; row++)
{
// Instantiate a hex
Hex h = new Hex (column, row);
Vector3 pos = h.PositionFromCamera (
Camera.main.transform.position,
numRows,
numColumns
);
GameObject hexGO = Instantiate (
HexPrefab,
pos,
Quaternion.identity,
this.transform
);
hexGO.GetComponent<HexComponent>().Hex = h; //These two lines aren't working
hexGO.GetComponent<HexComponent>().HexMap = this; //These two lines aren't working
MeshRenderer mr = hexGO.GetComponentInChildren<MeshRenderer> ();
mr.material = HexMaterials [Random.Range (0, HexMaterials.Length)];
}
}
}
}
First, please use code tags. See the first post in the forum.
Second, please try googling “NullReferenceException: Object reference not set to an instance of an object” as it is easily the most-asked question in this forum presently.
A construct like the above can also be broken apart into its constituent elements in order to see what might be null.
HexComponent hc = hexGo.Getcomponent<HexComponent>();
hc.Hex = h;
Now you know where it blows up.
Engineers must be masochistic at heart because for some crazy reason, a lot of engineers like to ball all those statements up on one line because they like to make debugging difficult, and I don’t understand it.
Break it all apart, like by line, so you can breakpoint it at ANY POINT, because a) the compiler will make it just as fast, and b) it might reveal to you that you have a bug!
So breaking it down, the first line gets the HexComponent component from the given game object.
If it fails on the second line, it means it was unable to find said HexComponent.
Now here are some possibilities:
there IS no HexComponent on the GameObject
the HexComponent is disabled, which means it won’t be found.
the GameObject this script is running on isn’t the one you think it is (i.e., you dropped this script on another object as well)… try using Debug.Log( name) right before this construct to reveal the name of the GameObject
The above thought processes are pretty common to almost every minute-to-minute development problem you find when working in Unity, so keep lists like this handy. You can easily spend as much time tracking down “plumbing” of GameObjects and Components as you do tracking down actual code bugs.
I can see what you mean about keeping track of the ‘plumbing’ - that’s definitely my biggest problem at the moment. I think it’s largely due to my lack of familiarity with Unity.
It seems like the script is now working - the only thing I did (other than adding lots of Debug.Log statements) is to hit apply on the HexPrefab. Could that have been enough to fix the problem? And if so why did it fix it?
It could have fixed it. So here’s some more Unity3D insight (and anyone else feel free to jump in and correct me or add to the discussion):
When you make a prefab, you are “snapshotting” a bunch of GameObjects and Components and their settings at that particular moment in time. It is not a “live” connection. It is just a onetime copy, as well as a link that says “I came from that prefab.”
When you drag that prefab into a scene, you are making a copy of that prefab, but the scene says “I look just like that Prefab, except I am located here.” I.e., the scene “overrides” the root transform only, and preserves the “I came from that prefab” link.
If you go into a prefab in your scene and move it, it moves that root transform, but it does not change the source prefab.
If you go into a prefab in your scene and change other parts of it, now ONLY THAT INSTANCE in your scene has those changes that you made. All other instances including the prefab itself, will have the base prefab values.
If you hit APPLY on an instance, the things that you changed on that instance will be copied to the base prefab, then every other instance that uses that base prefab will get those changes… EXCEPT other instances that override those particular changes.
tl;dr: It’s complicated, but it actually totally makes sense from a “take baseline and modify” approach.
PS - it also explains why the simple request for “nested prefabs” has not yet been met: it’s a hard problem to solve, because then you have prefabs that would need to contain the “changes” of other prefabs that happen to be inside of them, and then you have Prefab-ception.
Thanks Kurt - that does help explain what was happening. I have a lot of gaps in my understanding of Unity. I’m trying to go through tutorials to increase my understanding of how things work - but it’s a different way of thinking (for me.) It’ll take time to understand the various nuances of Unity, but then Rome wasn’t built in a day! Thanks again!
Indeed… been using it 5+ years now and still finding new insights. It’s an awesome environment to work in. The Unity guys have done an amazing job extending and enhancing a truly completely configurable development environment.