Reputation: 1
when i starting my game on the game scene,everything is fine,but when i load from menu,first time is ok,then there is saving data to json,and when i come back to main menu,and then again press play it's " Object reference not set to an instance of an object " for my saveScript which is attached to empty gameObject on game scene.
loading just
SceneManager.LoadSceneAsync("game");
SAVE SCRIPT
public void PopulateSaveData(SaveData sd)
{
//character
sd.s_XP = XP;
respawnScript.instance.PopulateSaveData(sd);
sd.s_x = gameObject.transform.position.x;
sd.s_y = gameObject.transform.position.y;
sd.s_z = gameObject.transform.position.z;
playerHealth.instance.PopulateSaveData(sd);
//sword
playerSword.instance.PopulateSaveData(sd);
//inventory
Inventory.instance.PopulateSaveData(sd);
//sd.s_allItemsPositions = allItemsPositions;
//sd.s_allPotionInteractions = GameObject.FindObjectsOfType<potionInteraction>().ToList();
if (allPotionInteractionO.Count > 0)
{
Debug.Log("ALL POTIONS COUNT " + allPotionInteractionO[0]);
sd.s_allPotionInteractions = allPotionInteractionO;
}
sd.s_allWeaponInteractions = all_swords;
sd.s_allWeaponInteractionsGO = all_swordsGO;
for (int i = 0; i < all_swordsGO.Count; i++)
{
sd.s_allSwordsRotation.Add(all_swordsGO[i].transform.rotation);
}
for (int i = 0; i < all_swordsGO.Count; i++)
{
//because some objects can be destroyed thats why im initializing list again
//allInteractableGameObjects = GameObject.FindGameObjectsWithTag("interactable object").ToList();
// sd.s_allItemsPositions.Add(allInteractableGameObjects[i].transform.position);
sd.s_allSwordsPositions.Add(all_swordsGO[i].transform.position);
}
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
sd.s_allPotionsPositions.Add(allPotionInteractionO[i].transform.position);
}
///going through list and check if there is used item,then saving its bool to another list at same position
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
if (allPotionInteractionO[i].isUsed)
{
allPotionsIsUsed[i] = true;
}
}
sd.s_allPotionsIsUsed = allPotionsIsUsed;
//quest part
for (int i = 0; i < allNPCS.Count; i++)
{
if (allNPCS[i].quest == null)
{
allNpcQuests[i] = null;
}
}
sd.s_allQuests = allNpcQuests;
if(MarieleQuest.instance.currentMarieleQuest!=null)
{
sd.s_currentQuest = MarieleQuest.instance.currentMarieleQuest;
}
foreach (Slot slot in slotsToSave)
{
slot.PopulateSaveData(sd);
}
//enemies
foreach (EnemyStats enemy in all_enemies)
{
enemy.PopulateSaveData(sd);
}
//procedural enemies
foreach (ProceduralStats enemy in all_procedural_enemies)
{
enemy.PopulateSaveData(sd);
}
}
LOAD
public void LoadFromSaveData(SaveData sd)
{
if (SceneManager.GetActiveScene().name == "game")
{
//character
XP = sd.s_XP;
if (sd.s_HP > 0)
{
playerHealth.instance.LoadFromSaveData(sd);
}
else if (sd.s_HP == 0)
{
playerHealth.instance.currentHealth = 100;
}
if (sd.s_respawnObject != null)
{
respawnScript.instance.LoadFromSaveData(sd);
}
if (sd.s_x != 0 && sd.s_y != 0 && sd.s_z != 0)
{
gameObject.transform.position = new Vector3(sd.s_x, sd.s_y, sd.s_z);
}
//sword
if (sd.s_sword != null && sd.s_temp != null && sd.s_currentSword != null && sd.s_currentSwordGO != null)
{
playerSword.instance.LoadFromSaveData(sd);
}
else
{
playerSword.instance.currentSwordGameObject = GameObject.Find("character/mixamorig:Hips/mixamorig:Spine/mixamorig:Spine1/" + playerSword.instance.currentSwordGameObject.name);
playerSword.instance.temp = playerSword.instance.currentSwordGameObject;
}
//potions
if (sd.s_allPotionsIsUsed.Count > 0)
{
allPotionsIsUsed = sd.s_allPotionsIsUsed;
}
//quest
if (sd.s_allQuests.Count > 0)
{
Debug.Log("SD ALL QUESTS" + sd.s_allQuests);
allNpcQuests = sd.s_allQuests;
}
if (sd.s_allQuests.Count > 0)
{
for (int i = 0; i < allNPCS.Count; i++)
{
allNPCS[i].quest = allNpcQuests[i];
}
}
if (sd.s_currentQuest != null)
{
MarieleQuest.instance.currentMarieleQuest = sd.s_currentQuest;
}
if (sd.s_allPotionInteractions.Count > 0)//second pattern in if is changed(FOR REMEMBER)
{
Debug.Log("SD ALL POTIONS > 0");
if (sd.s_allPotionInteractions[0] != null)
{
allPotionInteractionO = sd.s_allPotionInteractions;
}
else
{
allPotionInteractionO = GameObject.FindObjectsOfType<potionInteraction>().ToList();
}
for (int b = 0; b < allPotionInteractionO.Count; b++)
{
allPotionInteractionO[b].isUsed = allPotionsIsUsed[b];
}
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
if (allPotionInteractionO[i].isUsed)
{
allPotionInteractionO[i].gameObject.SetActive(false);
}
}
}
Inventory.instance.LoadFromSaveData(sd);
if (sd.s_allWeaponInteractions.Count > 0)
{
//all_swords = sd.s_allWeaponInteractions;
// all_swordsGO = sd.s_allWeaponInteractionsGO;
for (int i = 0; i < all_swordsGO.Count; i++)
{
if (!Inventory.instance.itemsGameObjects.Contains(all_swordsGO[i])
&& all_swordsGO[i] != playerSword.instance.currentSwordGameObject)
{
all_swordsGO[i].SetActive(true);
all_swordsGO[i].transform.rotation = sd.s_allSwordsRotation[i];
}
}
for (int j = 0; j < sd.s_allSwordsPositions.Count; j++)
{
//Debug.Log(sd.s_allItemsPositions[j] + " " + allInteractableGameObjects[j].name);
all_swordsGO[j].transform.position = sd.s_allSwordsPositions[j];
allPotionInteractionO[j].transform.position = sd.s_allPotionsPositions[j];
}
}
foreach (Slot slot in slotsToSave)
{
slot.LoadFromSaveData(sd);
}
//enemies
foreach (EnemyStats enemy in all_enemies)
{
enemy.LoadFromSaveData(sd);
}
foreach (string id in dead_enemies_ids)
{
SaveData.EnemyData enemyData = new SaveData.EnemyData();
enemyData.e_Health = 0;
enemyData.e_id = id;
sd.enemyData.Add(enemyData);
}
//procedural enemies
foreach (ProceduralStats enemy in all_procedural_enemies)
{
enemy.LoadFromSaveData(sd);
}
foreach (string id in all_procedural_ids)
{
SaveData.ProceduralEnemyData enemyData = new SaveData.ProceduralEnemyData();
enemyData.e_ProcHealth = 0;
enemyData.e_ProcId = id;
sd.proceduralEnemyData.Add(enemyData);
}
}
}
these two scripts just writing data to lists,and reading it from saved file,
saving is called once OnApplicationQuit()
load called at the end of Start()
when i open scene game just from itself and close and load again,everything work fine,because its destroying objects and load them again,but
once i start from main menu,from there do LoadScene("game") i'm getting error that some fields are not exist anymore,but it's like unreal
SaveData script which have all info and store it to file,then read
public class SaveData : MonoBehaviour
{
private void Awake()
{
}
private void Start()
{
s_inventoryGO = new List<GameObject>();
Debug.Log("s_inventoryGO" + s_inventoryGO.Count);
}
//character saving
public int s_XP;
public GameObject s_respawnObject;
public float s_x;
public float s_y;
public float s_z;
//inventory
public List<Item> s_inventory = new List<Item>();
public List<GameObject> s_inventoryGO = new List<GameObject>();
public List<GameObject> s_allGameObjectInventory = new List<GameObject>();
public List<GameObject> s_allInteractableObjects = new List<GameObject>();
public List<potionInteraction> s_allPotionInteractions = new List<potionInteraction>();
public List<weaponInteract> s_allWeaponInteractions = new List<weaponInteract>();
public List<GameObject> s_allWeaponInteractionsGO = new List<GameObject>();
public List<Quaternion> s_allSwordsRotation = new List<Quaternion>();
public List<Vector3> s_allSwordsPositions = new List<Vector3>();
public List<Vector3> s_allPotionsPositions = new List<Vector3>();
public List<bool> s_allPotionsIsUsed = new List<bool>();
public List<Quest> s_allQuests = new List<Quest>();
public Quest s_currentQuest;
public int s_HP;
[System.Serializable]
public struct SlotsData
{
public Item s_slotItem;
public string s_id;
//public Sprite s_icon ;
}
public List<SlotsData> s_slots = new List<SlotsData>();
//sword
public Transform s_sword;
public GameObject s_currentSwordGO;
public GameObject s_temp;
public swordEquipping s_currentSword;
//enemy saving
[System.Serializable]
public struct EnemyData
{
public int e_Health;
public string e_id;
}
public List<EnemyData> enemyData = new List<EnemyData>();
//procedural enemy saving
[System.Serializable]
public struct ProceduralEnemyData
{
public int e_ProcHealth;
public string e_ProcId;
}
public List<ProceduralEnemyData> proceduralEnemyData = new List<ProceduralEnemyData>();
public string toJson()
{
return JsonUtility.ToJson(this);
}
public void LoadFromJson(string json)
{
JsonUtility.FromJsonOverwrite(json, this);
}
}
Upvotes: 0
Views: 441
Reputation: 6275
When using DontDestroyOnLoad
wherever you want this object to exist, make a copy of it in your scene if you want the data stored to persist between your game session.
Here is a snippet from the docs
void Awake()
{
GameObject[] objs = GameObject.FindGameObjectsWithTag("music");
if (objs.Length > 1)
{
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
It will search for other objects in the scene with the same tag. If it finds it, it will destroy itself. What you can do here is have a public Init() function on your script. When a new scene is loaded with the object and your object already finds an instance of itself, it can pass the local references to the existing object. Something like...
public GameObject objRef1;
public GameObject objRef2;
public void Init(GameObject obj1, GameObject obj2)
{
objRef1 = obj1;
objRef2 = obj2;
...
etc.
}
Inside of the Awake()
of the new object, you would call the existing objects Init with the local references it has, which work as it loaded with your scene.
void Awake()
{
// make the tag unique so you only grab objects of this save type
GameObject[] objs = GameObject.FindGameObjectsWithTag("yourObjectsTag");
if (objs.Length > 1)
{
objs[0].GetComponent<YourScriptName>().Init(obj1, obj2, ..., etc.);
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
In this approach it means you have a local copy of your DontDestroyOnLoad object in every scene so when the existing one loads in, it can just grab the references from it.
Upvotes: 0