- Home /
Is there a reason why Unity would be able to read one variable in a script and not another?
I have a single script attached to a gamemanager object in my game that has two sections: one as a GameManager that holds data between scenes and one as a Serializable section which converts the data from the GameManager to enable the Save function to save it.
If I play the game through from scene 1 - scene 3 and then save, the variables are all successfully read by my Save function (in a separate script). If, however, I load a previous game, I run into problems. The data is successfully loaded into the game and I can play it (ie. the GameManager.control.xxxx variables successfully use the loaded data), but when I go to save again, I can't because the game cannot find the Serializable section (PlayerData.current.xxxx). ie. Unity says object reference is not set to an object for the following line of the Save function:
Debug.Log ("Saved Data: " + PlayerData.current.healthpotion);
This is despite the fact it's already accessed it to make the original save file. Is there any reason why a game wouldn't be able to see another section of the same script?
Main script
using UnityEngine;
using System.Collections;
public class GameManager : MonoBehaviour {
public static GameManager control;
//recording names
public string username;
//setting up potion score
public int hlthpotion;
public int mnpotion;
....
[System.Serializable]
public class PlayerData {
public static PlayerData current;
public string UserName;
public int healthpotion;
public int manapotion;
public bool redWizard;
public bool purpleWizard;
public bool blueWizard;
public PlayerData () {
UserName = GameManager.control.username;
redWizard = GameManager.control.redwizard;
blueWizard = GameManager.control.bluewizard;
purpleWizard = GameManager.control.purplewizard;
healthpotion = GameManager.control.hlthpotion;
manapotion = GameManager.control.mnpotion;
}
}
Loading/Saving script
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public static class SaveLoad {
public static List<PlayerData> savedGames = new List<PlayerData> ();
public static void Save () {
Debug.Log ("Original Data: " + GameManager.control.hlthpotion);
Debug.Log ("Saved Data: " + PlayerData.current.healthpotion);
PlayerData.current.healthpotion = GameManager.control.hlthpotion;
PlayerData.current.manapotion = GameManager.control.mnpotion;
Debug.Log ("Game To Be Saved");
Debug.Log ("Original Data" + GameManager.control.hlthpotion);
Debug.Log ("Saved Data" + PlayerData.current.healthpotion);
SaveLoad.savedGames.Add (PlayerData.current);
Debug.Log ("Game Added");
BinaryFormatter bf = new BinaryFormatter ();
FileStream file = File.Create (Application.persistentDataPath + "/playerInfo.dat");
bf.Serialize (file, SaveLoad.savedGames);
file.Close ();
Debug.Log ("Game Saved " + PlayerData.current.UserName);
}
public static void Load() {
if (File.Exists (Application.persistentDataPath + "/playerInfo.dat")) {
Debug.Log ("Save File exists");
BinaryFormatter bf = new BinaryFormatter ();
FileStream file = File.Open (Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
// SaveLoad.savedGames = (List<PlayerData>)bf.Deserialize (file);
List<PlayerData> playerDataList = (List<PlayerData>)bf.Deserialize (file);
file.Close ();
Debug.Log ("Save File Closed");
foreach (PlayerData Pd in playerDataList) {
GameManager.control.username = Pd.UserName;
Debug.Log ("Username matched");
GameManager.control.redwizard = Pd.redWizard;
Debug.Log ("Red matched");
GameManager.control.bluewizard = Pd.blueWizard;
Debug.Log ("Blue matched");
GameManager.control.purplewizard = Pd.purpleWizard;
Debug.Log ("Purple matched");
GameManager.control.hlthpotion = Pd.healthpotion;
Debug.Log ("Health Potion = " + GameManager.control.hlthpotion);
GameManager.control.mnpotion = Pd.manapotion;
// Debug.Log ("Mana Potion: " + PlayerData.current.manapotion);
}
}
}
}
You don't set PlayerData.current anywhere so it will be null, therefore PlayerData.current.xxxxx doesn't exist.
I thought that might be it and tried setting it, but couldn't work out what I could set it to that would work. I tried setting PlayerData.current = Pd within the foreach loop, and that got me an "Object Reference not set to object" error. What else could I try setting it to.
Surely your current one is whichever you are choosing to load? I'm not sure why you are loading all your Pd's anyway, Game$$anonymous$$anager.control will just be overriden each time and you will only ever be able to load the most recently saved data.
Can you add Debug.Log(Pd) in your foreach and see if it's null?
Answer by FortisVenaliter · Aug 20, 2015 at 10:17 PM
It's because static fields are not serialized. What you can do is instead of having that as a static field in the PlayerData class, put it as a non-static field in the GameManager (which I assume is a singleton?). Then, if you want to keep references, you can just modify the old current variable as such:
public static PlayerData current { get { return GameManager.singleton.playerData; } }
Or something like that. Then all references would work, and it should serialize properly.