I have a Game Object prefab called ‘Room’ with a class attached to it.
Within that Room class are these four lines:
public bool northExit = false;
public bool southExit = false;
public bool eastExit = false;
public bool westExit = false;
From a different class on a separate prefab, MainGame, I instantiate Room using:
public GameObject room;
void Start(){
Instantiate(room);
}
And I assign my Room prefab to the GameObject room variable in the inspector.
Back in the Room class I set the north/south/east/westExit variables posted above to true on a keypress. This works fine, they are set from false to true - checked with Debug.Log - and the program functions as expected when I test it.
But once I unclick the play button in Unity, and end the scene testing, those variables REMAIN set to true the next time I test the scene. Looking at the Room prefab in the inspector shows that indeed those variables are set to true, and they do not reset to false as specified in the Room class.
I even tried setting the Exit variables to false in the Start() of the Room class and they still do not reset to false when I instantiate the Room prefab.
The Exit variables will only reset when I shut down Unity and reopen it.
Is this a bug, or could I be doing something wrong?
Yes, what @StarManta said… if after you Instantiate(room) then you go on and manipulate room member variables directly, you are actually modifying the prefab on disk.
What you generally want is to make an instance of the room like so:
GameObject roomInstance = Instantiate( room);
For that matter, you could just “recycle” the variable, but that is not great coding practice:
room = Instantiate( room);
which will throw out your original reference to the room prefab once you are running, clone it, and then all your changes to it will NOT affect the on-disk resource.
I recommend renaming the public variable to something like RoomTemplate or RoomPrefab to make it clear you don’t want to use that one in your script directly, and then make a new variable like RoomTemplate. Unity’s tutorials are notoriously confusing on this because they are trying to keep the variable names simple and short, and the obscure important subtleties like the above.
This is the Room class I have attached to my prefab (minus a few other methods that dont touch the exit variables).
public class Room : MonoBehaviour {
public bool northExit = false;
public bool southExit = false;
public bool eastExit = false;
public bool westExit = false;
public int ranAmount;
public int ranDirection;
public List<string> exitDirections = new List<string> ();
public Count exitsCount = new Count (1,4);
[System.Serializable]
public class Count{
//Create the min & max variables
public int minimum;
public int maximum;
//Assignment constructor used to declare min and max when declaring a new count
public Count (int min, int max){
//Set the variables
minimum = min;
maximum = max;
}
}
//Add the exit directions to a list so we can pick randomly from the list later
void initialiseExitDirections(){
exitDirections.Clear();
exitDirections.Add ("North Exit");
exitDirections.Add ("South Exit");
exitDirections.Add ("East Exit");
exitDirections.Add ("West Exit");
}
void PlaceExits(){
//Init the exit directions
initialiseExitDirections()
//How many exits should this room have (1-4)
ranAmount = Random.Range (exitsCount.minimum, exitsCount.maximum);
//Create a random Number to grab N, S, E, or W
ranDirection = Random.Range (0, exitDirections.Count);
for(int i = 0; i<ranAmount; i++) {
if (exitDirections [ranDirection] == "North Exit") {
northExit = true;
}
if (exitDirections [ranDirection] == "South Exit") {
southExit = true;
}
if (exitDirections [ranDirection] == "East Exit") {
eastExit = true;
}
if (exitDirections [ranDirection] == "West Exit") {
westExit = true;
}
}
}
}
So you’re saying that I cannot alter the variables of my Room class from INSIDE my Room class? That even after I have instantiated the Room prefab containing the Room class, that altering the Room class will alter the class on the stored prefab?
That seems rather… counter-intuitive. So I need to alter the variables on my Room instances from OUTSIDE of the Room class? Ugh. That’s really annoying and obtuse.
edit:
Alright, so I moved all of my exit variable modifiers in to a separate Exit class, I pass the exit variables from the Room class in to the Exit class for computation, and then have the Exit class return the values to my Room class so it can set the exit variables, and that seems to have sorted the issue out.
Have to say I still find the whole set up rather annoying. I would much rather have each instantiated prefab have its own instantiated class attached.
It has nothing to do with where you CAN do anything. It has to do with what you are doing the modifying upon.
Based on you seeing the variables change on the disk asset (in your original post, how you notice the next time you set the scene, they have been changed), I suggested that you clarify what you are doing.
Saying “Instantiate(room);” does NOT in fact modify the room variable in any way. That still points to the disk copy, if you se the prefab. Any attempts to change its variables will in fact change its on-disk properties.
My second example of “room = Instantiate(room);” will clone the reference and use that from now on until you end running. That is the LIKELY thing you want to have happen.