I turned the non-static field to static to make sure this is the only one being used. I only have one GameObject in the scene hierarchy that uses this Class Component.
public class GameManager : MonoBehaviour
{
private static GameObject _redLightBall;
private static GameObject _blueLightBall;
This is the function that re-assigns _redLightBall and checks for null and value.
private void analyzeLevelData()
{
resetFlags();
if (!_levelDataInitialized)
{
_redLightBall = GameObject.FindGameObjectWithTag("RedBall");
_blueLightBall = GameObject.FindGameObjectWithTag("BlueBall");
if (_redLightBall == null)
{
Debug.Log("DID NOT FIND RED BALL: " + _redLightBall);
}
else { Debug.Log("Red Light Ball is: " + _redLightBall); }
Debug.Log("LEVEL DATA INITIALIZED BY: " + transform.root.gameObject.name);
_levelDataInitialized = true;
}
}
Now, here is the Update function that checks if the level data is initialized first before executing the game mechanics/logic.
public void Update()
{
if (_levelDataInitialized)
{
if (_redLightBall == null)
{
Debug.Log("RED BALL IS: " + _redLightBall);
Debug.Log(transform.root.gameObject.name);
}
if (_redLightBall.transform.position == _redPointPositions[1].position)
{
_redDiodeOffEnd.SetActive(false);
_redDiodeOnEnd.SetActive(true);
When the execution reached the Update function, _redLightBall no longer has the value and returns null, which is strange that I cannot make the sense out of.
Update function checks _levelDataInitialized == true set by analyzeLevelData() before proceeding to execute the body. After all that, the error still occurs.
Note: the first generated level which is analyzed by analyzeLevelData() and executed by Update() does not produce any null errors, the second time around will.
It feels like Update() does not realize that _redLightBall which was previously destroyed already has a new re-assigned value.
public void GenerateLevel(int levelNumber, string levelName)
{
if (_levelParent != null)
{
Destroy(_levelParent);
Debug.Log("COMPLETED LEVEL DESTROYED.. ");
This GenerateLevel() function destroys the existing level first before generating a new one.
I am sure that the Destroy(_levelParent) is called only once right after I clicked "Next Level" button. And as you can see there is no Log indicating that the Destroy() function is called right in between checks of _redLightBall.
The quick one liner fix is:
Invoke("analyzeLevelData", 0.5f);
Since Update() waits on the flag that analyzeLevelData() sets to true, I made a slight delay to wait for _levelObject to be destroyed. Re-initialized level data would then be not lost caused by Destroy() being effective at the start of the next frame.
Can we do better than this to make sure this frame-related bug will not re-occur?
AnalyzeLevelData
in the same frame as the scene load, so it's capturing a reference to the old RedBall object that's about to be unloaded at the end of the frame, instead of the new RedBall that's about to be loaded in the new scene? I've encountered similar errors before with code that assumes thatLoadScene
replaces the scene instantly, rather than after the current frame finishes executing. \$\endgroup\$