OK, so this is a weird one. Seems like a potential bug but I don’t know.
I have 2 scripts: PosTracker.cs and TerrainMgr.cs . The details are not terribly important but I am having some weird behavior with the variables.
In one script I have a variable which is getting a value from a method in the other script:
public class PosTracker : MonoBehaviour
{
public GameObject terrainManager;
public int lastSwapped;
public int myTerrain;
public int prevTerrain;
private int numOfTerrains;
// Start is called before the first frame update
void Start()
{
numOfTerrains = GameObject.Find("TerrainManager").GetComponent<TerrainMgr>().GetNumTerrains();
Debug.Log(numOfTerrains);
}
the TerrainManager gameObject has a TerrainMgr.cs on it which has:
public class TerrainMgr : MonoBehaviour
{
float zCounter;
public List<Terrain> terrains;
int randTerrain;
public Terrain[] spawnedTerrains;
[SerializeField]
private int numTerrains;
// Start is called before the first frame update
void Start()
{
numTerrains = 12;
}
public int GetNumTerrains()
{
return numTerrains;
}
The problem here is that when I hit Play, I can see in the Inspector that numTerrains has been set to “12”.
But for some reason, GameObject.Find(“TerrainManager”).GetComponent().GetNumTerrains(); always returns “4” as the value.
I put in Debug.Log statements to confirm:

Previously, when writing this code, “numTerrains” in the TerrainMgr script WAS set to a public int with a value of 4.
Even after refactoring this code a bunch of times though, I always get “4” instead of “12” here. I can’t figure this one out.
I have searched all the scripts in this scene (there are only 2) and nowhere does this (or any) variable get set to a value of 4, so where the heck is it getting that from?? It’s like it is “holding on” to the previous public int value somehow.
By the way, when looking at my TerrainMgr script in the Inspector it looks like:
I cannot for the life of me figure out where that “4” is coming from.
This is the entire script currently.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TerrainMgr : MonoBehaviour
{
float zCounter;
public List<Terrain> terrains;
int randTerrain;
public Terrain[] spawnedTerrains;
[SerializeField]
private int numTerrains = 0;
// Start is called before the first frame update
void Start()
{
numTerrains = 12;
spawnedTerrains = new Terrain[numTerrains];
zCounter = 0f;
Debug.Log(zCounter);
for (int i = 0; i < numTerrains; i++)
{
Debug.Log("i is" + i);
randTerrain = Random.Range(0, terrains.Count);
Debug.Log("Random " + randTerrain);
// Debug.Log("Terrains Count: " + terrains.Count);
spawnedTerrains[i] = Instantiate(terrains[randTerrain], new Vector3(0, 0, zCounter), Quaternion.identity); // pick a random terrain and instantiate it at 0,0,( z counter )
spawnedTerrains[i].gameObject.SetActive(true);
zCounter += 500f;
}
}
// Update is called once per frame
void Update()
{
Debug.Log("TMGR: " + numTerrains); // this spits out "12" reliably even though it says "4" in inspector
}
public void swapOutTerrain(int _terrain)
{
if (_terrain == 0) // if swapping #1 we also swap the buffer
{
randTerrain = Random.Range(0, terrains.Count);
Destroy(spawnedTerrains[_terrain].gameObject);
Destroy(spawnedTerrains[numTerrains - 1].gameObject);
spawnedTerrains[_terrain] = Instantiate(terrains[randTerrain], new Vector3(0, 0, _terrain * 500), Quaternion.identity); // pick a random terrain and instantiate it at 0,0,( z counter )
spawnedTerrains[_terrain].gameObject.SetActive(true);
spawnedTerrains[numTerrains - 1] = Instantiate(terrains[randTerrain], new Vector3(0, 0, (numTerrains - 1) * 500), Quaternion.identity);
spawnedTerrains[numTerrains - 1].gameObject.SetActive(true);
Debug.Log("Swapped buffer");
} else
{
randTerrain = Random.Range(0, terrains.Count);
Destroy(spawnedTerrains[_terrain].gameObject);
spawnedTerrains[_terrain] = Instantiate(terrains[randTerrain], new Vector3(0, 0, _terrain * 500), Quaternion.identity); // pick a random terrain and instantiate it at 0,0,( z counter )
spawnedTerrains[_terrain].gameObject.SetActive(true);
Debug.Log("Swapped terrain " + _terrain);
}
}
public int GetNumTerrains()
{
return numTerrains;
}
}
Well I guess that’s a bug. I removed the TerrainMgr component from the TerrainManager game object, and added it back, and now it shows “0” for numTerrains until I press play and it goes to 12. what the heck!
Unity 2019.4.20f1
If you set numTerrains to public and then right click/reset on the header, what is the value of numTerrains?
The 4 is right there in your screenshot:
The problem with your code is that there is by default no defined order in which Start methods on different scripts run. It may run. So basically your Start method that is reading the 4 happens before the other Start method that writes the 12.
If you have a serialized field, you should just set the value in the inspector.
1 Like
I only serialized it so I could see it easily. The point is that it remained at "4"and remained visible in the inspector even after I had changed it to private. The inspector wasn’t updating until I removed the script and added it back.
Now that is definitely weird. If you’re positive you saved the script after changing the variable to private and removing [SerializeField] on it, then yeah Unity didn’t update the Inspector correctly.
If it remained visible in the inspector after changing it to private you never successfully recompiled your scripts after the change. Maybe you forgot to save the file for example. Everything you’ve described has been consistent with the value simply being serialized as 4 and an execution order bug in your code.
Yeah, sorry, but no. You’ve made an assumption about what the cause must be and are trying to fit the situation to that assumption. I struggled with this for a good hour. I modified, saved, and recompiled both my scripts a dozen or more times each. This was a Unity inspector issue, nothing more.