- Home /
Saving a List of variables between scenes
I am making a small airport simulator, for that I have three scenes that i jump back and forth between (three menus so to speak). One of these is an interactive map where you can assign flight routes, however, when I change to another menu my flight routes has been deleted because unity clears all objects.
So I sat up a controller object which uses the "DoNotDestroyOnLoad" method which is quite handy, however, every flight is represented by a small plane, which also stores all the relevant flight data. (Using DoNotDestroyOnLoad on each plane is not that smart as they will then appear in the other menus) - I store these flights as a list of gameobjects in the controller object - but to no surprise all the gameojects are missing when you change scene and change back again - SO i made another list that contains a variables instead of gameobjects. These variables are a custom script that contain all the relevant data for a flight route, and then I store that. If I then try to instantiate planes from this list it works fine, however, if I change scene and go back again, it tells me that I get a NullReferenceExpectation - which is annoying because that means the list of variables are being cleared every time I change scene - how do I prevent that from happening? :O
Here is my controller script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class controllerScript : MonoBehaviour {
private static bool created = false;
public GameObject smallPlanes;
public GameObject mediumPlanes;
public GameObject largePlanes;
public bool instansiated = false;
public List<GameObject> flights;
public List<AirplaneClassScript> temp;
void Awake(){
if (!created) {
// this is the first instance - make it persist
DontDestroyOnLoad(this.gameObject);
created = true;
} else {
// this must be a duplicate from a scene reload - DESTROY!
Destroy(this.gameObject);
}
}
void Start(){
flights = new List<GameObject>();
temp = new List<AirplaneClassScript>();
}
public void instantiatePlanes(){
foreach(AirplaneClassScript planeTemp in temp){
GameObject newPlane;
switch(planeTemp.type){ // <--- here it gives me a nullref error
case("small"):
newPlane = (GameObject)Instantiate(smallPlanes);
break;
case("medium"):
newPlane = (GameObject)Instantiate(mediumPlanes);
break;
case("large"):
newPlane = (GameObject)Instantiate(largePlanes);
break;
}
}
}
}
Here is my variable script which stores everything that is relevant for the flight:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class AirplaneClassScript : MonoBehaviour {
public string type;
public int maxPax, maxCargo, travelCost, speed;
public List<string> route;
public bool pax, cargo, mix;
public int FH;
public int startTurn;
public Vector3 currentPosition;
void Awake(){
DontDestroyOnLoad(this.gameObject);
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
Thanks a lot in advance! :)
A couple of points:
1) AirplaneClassScript should probably not derive from $$anonymous$$onoBehaviour - it's just a class containing some data, isn't it? Not something that gets attached to a GameObject. If you make it a normal class then you can use it to carry data between the scenes without having to call DontDestroyOnLoad on all of its instances. Of course then it won't get Awake/Start/Update calls, you just access it from other GameObjects.
2) I don't see you putting anything into your "flights" list anywhere, is that an oversight?
3) I don't see any calls to instantiatePlanes. It's also odd that it is looping over the "temp" list, which was cleared in Start(). Does something else populate the "temp" list and call instantiatePlanes?
It's not really possible to guess why you're getting NullReferenceExceptions without knowing at least where the function is called from, and what is in the "temp" list at the time.
Answer by Ollenator · Jan 13, 2014 at 12:07 PM
Thanks for the reply, I will adress your points in the same structure :)
1) Good point, yes it just contains data, so it is silly to make it derive from monobehaviour :) thanks for pointing that out.
2) I do that through another script, it is quite long but here is the relevant part, which also answers your last question
case("Map"):
if(GUI.Button(new Rect(Screen.width - 65, 15, 50, 50), "X")){
GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>().instantiatePlanes();
}
if(!GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>().instansiated){
GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>().instantiatePlanes();
GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>().instansiated = true;
}
if(GUI.Button(new Rect(15.0f, 15.0f, 100.0f, 25.0f), "Small Planes")){
flightOption = true;
controllerScript controlScript = GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>();
newPlane = (GameObject)Instantiate(smallPlane);
newPlaneTemp = new AirplaneClassScript();
controlScript.flights.Add(newPlane);
controlScript.temp.Add (newPlaneTemp);
newPlaneTemp.type = newPlane.tag;
newPlaneTemp.startTurn = newPlane.GetComponent<AirplaneScript>().startTurn;
}
if(GUI.Button(new Rect(15.0f, 45.0f, 100.0f, 25.0f), "Medium Planes")){
flightOption = true;
controllerScript controlScript = GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>();
newPlane = (GameObject)Instantiate(mediumPlane);
newPlaneTemp = new AirplaneClassScript();
controlScript.flights.Add(newPlane);
controlScript.temp.Add (newPlaneTemp);
newPlaneTemp.type = newPlane.tag;
}
if(GUI.Button(new Rect(15.0f, 75.0f, 100.0f, 25.0f), "Large Planes")){
flightOption = true;
controllerScript controlScript = GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>();
newPlane = (GameObject)Instantiate(largePlane);
newPlaneTemp = new AirplaneClassScript();
controlScript.flights.Add(newPlane);
controlScript.temp.Add (newPlaneTemp);
newPlaneTemp.type = newPlane.tag;
}
if(flightOption){
GUI.Box(new Rect(Screen.width/2 - 125, Screen.height/2 - 75, 250, 150), "Select Type");
if(GUI.Button(new Rect(Screen.width/2 - 50, Screen.height/2 - 30, 100, 25), "PAX")){
newPlane.GetComponent<AirplaneScript>().pax = true;
newPlaneTemp.pax = true;
flightOption = false;
routeOption = true;
}
if(GUI.Button(new Rect(Screen.width/2 - 50, Screen.height/2, 100, 25), "Cargo")){
newPlane.GetComponent<AirplaneScript>().cargo = true;
newPlaneTemp.cargo = true;
flightOption = false;
routeOption = true;
}
if(GUI.Button(new Rect(Screen.width/2 - 50, Screen.height/2 + 30, 100, 25), "Mix")){
newPlane.GetComponent<AirplaneScript>().mix = true;
newPlaneTemp.mix = true;
flightOption = false;
routeOption = true;
}
}
if(routeOption){
if(GUI.Button(new Rect( Screen.width/2 - 125, 50, 100, 50), "Complete Route")){
print ("complete route");
newPlane.transform.position = new Vector3(GameObject.Find(newPlane.GetComponent<AirplaneScript>().route[0]).transform.position.x, GameObject.Find(newPlane.GetComponent<AirplaneScript>().route[0]).transform.position.y, -2);
newPlaneTemp.currentPosition = newPlane.transform.position;
newPlaneTemp.route = newPlane.GetComponent<AirplaneScript>().route;
routeOption = false;
newPlane = null;
newPlaneTemp = null;
}
if(GUI.Button(new Rect( Screen.width/2 + 25, 50, 100, 50), "Cancel")){
controllerScript controlScript = GameObject.FindGameObjectWithTag("controller").GetComponent<controllerScript>();
controlScript.flights.Remove(newPlane);
controlScript.temp.Remove(newPlaneTemp);
Destroy(newPlane);
newPlane = null;
newPlaneTemp = null;
routeOption = false;
}
}
break;
}
This code is handling the GUI of the game, and it is through here that the function calls comes.
3) something else populates it, but do you mean to say it is clearing itself on every start()? I guess it does, but if it does - but then again in the inspector it does state it has the correct number of variables stored, just that they are missing. (well for gameObjects it states missing, for variables it does not state so)
Answer by Ollenator · Jan 13, 2014 at 12:07 PM
UPDATE!
making the variable script just a script, meaning I do not derive from monoBehaviour seems to have fixed the problem :) thanks a lot for the help :)
Your answer
Follow this Question
Related Questions
DontDestroyOnLoad() does not seem to be working. 3 Answers
FindGameObjectsWithTag not finding a tagged object 4 Answers
DontDestroyOnLoad duplication. 0 Answers
Next LEVEL Load Problem. 2 Answers
Setting public GameObject to a different Prefab through code 0 Answers