- Home /
Clicking out and then in to the Unity Player while game is running will something throw me a Null Exception.
Hello,
happy new year to all of you!
I have this problem an the script background_beha. When I leave the Unity Player running while I check on my script in Mono Develop and click back to the player to continue playing, it sometimes throws me a Null Exception. After Debbuging it seems that "Grid" is null inside the Grid Class, while accessing the method NodeFromWorldPoint(). It is pretty weird and I don't have any clue on how to debug this.
When I play the game and don't switch windows or do any other stuff on the computer everything runs fine. The error only appears when I click in and out of the Unity Player Window.
As a background, the Grid Class:MonoBehaviour is a Component of the A* GameObject. In its Start() it Instantiate the Background Sprite (which has the background_beha Script attached) like this:
void CreateBuild() {
grid = new Node[gridSizeX, gridSizeY];
worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.up * gridWorldSize.y / 2;
for (int x = 0; x < gridSizeX; x++) {
for (int y = 0; y < gridSizeY; y++) {
Vector3 worldPoint = worldBottomLeft + Vector3.right * (x*nodeDiameter+nodeRadius) + Vector3.up *(y*nodeDiameter+nodeRadius);
Vector3 snapPoint = worldBottomLeft + Vector3.right * (x*nodeDiameter+nodeDiameter) + Vector3.up *(y*nodeDiameter+nodeDiameter);
grid [x, y] = new Node (worldPoint, true, x, y,snapPoint,primaryElement);
Instantiate (gridTexture.gameObject, grid[x,y].getWorldCoor (), Quaternion.Euler (Vector3.zero),gridParent);
Instantiate (backgroundSprite.gameObject, grid[x,y].getWorldCoor (), Quaternion.Euler (Vector3.zero),backgroundParent);
}
}
gridParent.gameObject.SetActive (false);
}
Here the NodeFromWorldPoint() inside the Grid Class:
public Node NodeFromWorldPoint (Vector3 _worldPosition) {
float percentX = (_worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
float percentY = (_worldPosition.y + gridWorldSize.y / 2) / gridWorldSize.y;
percentX = Mathf.Clamp01 (percentX);
percentY = Mathf.Clamp01 (percentY);
int x = Mathf.RoundToInt((gridSizeX - 1) * percentX);
int y = Mathf.RoundToInt((gridSizeY - 1) * percentY);
return grid [x, y];
}
And here is the background_beha Class that is part of the backgroundSprite that is instantiated inside the Grid.
public class background_beha : MonoBehaviour {
public Sprite day,night;
public GameObject ResText;
public GameObject CoordText;
public GameObject WeightPenaltyText;
public GameObject elementIcon;
public Vector3 localSlotLocation2;
public Vector3 localSize = new Vector3 (0.4f, 0.4f, 1f);
[SerializeField]
private int showStatus = 0;
private Grid theGrid;
private Node currentNode;
private Transform refObject;
private float worldSizeX;
private SpriteRenderer sr;
private Inventory inventory;
private List<GameObject> localSlot2 = new List<GameObject>();
// Use this for initialization
void Start () {
ResText.SetActive (false);
CoordText.SetActive (false);
WeightPenaltyText.SetActive (false);
Setting_Button_Controller.showRessourceCap += Setting_Button_Controller_showRessourceCap;
refObject = GameObject.Find ("Night0.1Ref").transform;
sr = GetComponent<SpriteRenderer> ();
theGrid = GameObject.Find ("A*").GetComponent<Grid> ();
currentNode = theGrid.NodeFromWorldPoint (transform.position);
worldSizeX = theGrid.gridWorldSize.x;
inventory = currentNode.inventory;
}
void Setting_Button_Controller_showRessourceCap ()
{
if (showStatus < 2)
showStatus++;
else
showStatus = 0;
switch (showStatus) {
case 0:
ResText.SetActive (false);
CoordText.SetActive (false);
WeightPenaltyText.SetActive (false);
break;
case 1:
ResText.SetActive (true);
CoordText.SetActive (true);
WeightPenaltyText.SetActive (false);
break;
case 2:
ResText.SetActive (false);
CoordText.SetActive (true);
WeightPenaltyText.SetActive (true);
break;
}
}
void Update() {
float dif = Mathf.Abs (refObject.position.x - transform.position.x);
float alpha = Mathf.Sin (dif * Mathf.PI / worldSizeX);
if (currentNode == null) {
// HERE THE ERROR APPEARS !! //
Debug.LogError ("currentNode is null!");
theGrid = GameObject.Find ("A*").GetComponent<Grid> ();
currentNode = theGrid.NodeFromWorldPoint (transform.position);
}
if (alpha >= 0.5) {
sr.sprite = day;
currentNode.isNight = false;
} else {
sr.sprite = night;
currentNode.isNight = true;
}
ResText.GetComponent<TextMesh> ().text = currentNode.inventory.Count(currentNode.primaryElement).ToString();
Vector2 gridPos = currentNode.getGridPosition ();
CoordText.GetComponent<TextMesh> ().text = Mathf.RoundToInt (gridPos.x) + "," + Mathf.RoundToInt (gridPos.y);
WeightPenaltyText.GetComponent<TextMesh> ().text = currentNode.movementPenalty.ToString ();
}
void ShowInv() {
int counter = 0;
foreach (Element _e in inventory.AllElementsinInventory()) {
if (_e != currentNode.primaryElement) {
//print (gameObject.name+ ":found Element in Inventory: " + _e.elementName);
GameObject tempSlot = localSlot2.Find (i => i.name == "LocalSlot_" + _e.name);
if (tempSlot == null) {
tempSlot = (GameObject)Instantiate (elementIcon, transform);
tempSlot.transform.localScale = localSize;
tempSlot.transform.localPosition = localSlotLocation2 + new Vector3 (localSlotLocation2.x + 2 * counter, localSlotLocation2.y, localSlotLocation2.z);
tempSlot.name = "LocalSlot_" + _e.name;
tempSlot.GetComponent<ElementBehaivor> ().Element = _e;
tempSlot.GetComponent<ElementBehaivor> ().Amount = inventory.Count (_e);
localSlot2.Add (tempSlot);
} else {
if (inventory.Count (_e) > 0) {
tempSlot.SetActive (true);
tempSlot.transform.localPosition = localSlotLocation2 + new Vector3 (localSlotLocation2.x + 2 * counter, localSlotLocation2.y, localSlotLocation2.z);
tempSlot.GetComponent<ElementBehaivor> ().Amount = inventory.Count (_e);
counter++;
} else {
tempSlot.SetActive (false);
}
}
}
}
}
}
Project Background:
Prototyping Stage, A kind of city builder/strategy game. Doing it in my free time. First time developing a game. 10+ experience developing/designing/implementing business applications. I know the code is ugly.
Thanks for the help on guiding me where to keep digging into this.
Christian
The only thing in that function not declared in the function's scope is gridWorldSize. It's not set anywhere in your code above, where / when are you declaring it?
Answer by Glurth · Jan 02, 2018 at 05:47 PM
You mention this only happens sometimes.. is it possible his only occurs when you save a change to code? If the code gets recompiled, while in play-mode in the editor, it will reserialize everything. If the Node class does properly serialize, this would cause references to instances of it, to become null.
If the code gets recompiled, while in play-mode in the editor, it will reserialize everything.
Can that happen? I will try to reproduce...
Yes! I could reproduce the error. I changed the code, saved and it recompiled in the background. 2 sec later the error appeared! Wow. Never thought of this, this means could do changes on the fly without restarting the game every time.
Thanks!
Dont forget to accept the answer if it was the one!
Answer by meat5000 · Jan 02, 2018 at 12:55 PM
Try checking the Run In Background option.
https://docs.unity3d.com/ScriptReference/Application-runInBackground.html
This should keep things ticking over when focus is lost.
As an alternative, you can snapshot the variables that are giving you the trouble and feed them in; sort of using a dummy variable but using the last given information.
There is a method to do this
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationFocus.html
and a read-only bool if you want to check the status of focus
https://docs.unity3d.com/ScriptReference/Application-isFocused.html
When something will break if not supplied with constant information, add a '[catch][1]', either programming-literal or of your own creation; something as simple as an 'if null' or 'if !object'. Some level of pre-testing in the code will usually prevent these situations. [1]: https://www.google.co.uk/search?q=programming+catch&ie=utf-8&oe=utf-8&client=firefox-b&gfe_rd=cr&dcr=0&ei=ln9LWpWXMaPP8AfA8L6ACg
Thx for the quick answer. the Option "Run In Background" is turned on. I leave the game running in background while I check the code.
If Null is active, that is the weird thing, look at line 75 of background_beha.
I am implementing a Contructor that assigned the Grid and Node called by the upper Grid Class. $$anonymous$$aybe this will change the behavior or guide me somewhere. Try/Catch will be my next approach. Thx
Is it an actual error that is thrown up or just the Debug.Log?
Have two Node variables. At the end of the frame make
currentNode = lastNode;
If this does not solve the problem you need to Debug Log a bit deeper to see where the loss of information occurs.