Hi Joel,
Your whole example for "Creating an Automatic Save Structure" works great until it comes to manually saving and loading instead of On Start loading and OnApplicationQuit method. I shall explain the problem I am having and hopefully you can help me out, please...
I don't want automatic saves and loads, so I have changed the methods to something that is called manually. So OnStart and OnApplicationQuit are no more. I have replaced them with LoadUniqueObjects() and SaveUniqueObjects(). LoadUniqueObjects() is called by my ProfileMenuManagement script when a player chooses to load a saved game and SaveUniqueObjects() is called by my ProfileMenuManagement script when the player pauses/presses the escape key.
This works fine once. However after loading up the saved game and attempting to save it again, it throws an error and will not save anymore prefabs.
The error in question is:
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
UnityEngine.GameObject.GetComponent[ES2UniqueID] () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/GameObjectBindings.gen.cs:35)
UniqueSaveManager.SaveObject (UnityEngine.GameObject obj, Int32 i, System.String file) (at Assets/Easy Save 2/Examples/Creating an Automatic Save Structure/UniqueSaveManager.cs:99)
UniqueSaveManager.Save () (at Assets/Easy Save 2/Examples/Creating an Automatic Save Structure/UniqueSaveManager.cs:89)
UniqueSaveManager.SaveUniqueObjects () (at Assets/Easy Save 2/Examples/Creating an Automatic Save Structure/UniqueSaveManager.cs:28)
ProfileMenuManagement.SaveProfile1 () (at Assets/_FallenAngel/Scripts/MAIN/ProfileMenuManagement.cs:338)
ProfileMenuManagement.Update () (at Assets/_FallenAngel/Scripts/MAIN/ProfileMenuManagement.cs:116)
The line of code it is complaining about is this:
Code: Select all
// Let's get the UniqueID object, as we'll need this.
ES2UniqueID uID = obj.GetComponent<ES2UniqueID>();
And for reference, here is the UniqueSaveManager Script with all of the changes I have made:
Code: Select all
using UnityEngine;
using System.Collections;
/*
* This class will handle the saving and loading of data.
*/
public class UniqueSaveManager : MonoBehaviour
{
// For instancing this Script so that others can communicate with it.
public static UniqueSaveManager Instance;
//Player Profile Reference.
public string activeProfile;
public string sceneObjectFile = "sceneObjectsFile.txt";
public string createdObjectFile = "createdObjectsFile.txt";
void Awake()
{
Instance = this;
}
//This is where we save certain aspects of our instantiated prefabs.
public void SaveUniqueObjects()
{
Save();
}
/* We also save on application pause in iOS, as OnAppicationQuit isn't always called */
#if UNITY_IPHONE && !UNITY_EDITOR
public void OnApplicationPause()
{
Save();
}
#endif
/*
* This is where we'll load our data.
*
*/
public void LoadUniqueObjects()
{
/*Myk: This gets the Active Player Profile number from the Profile Menu Manager and converts
it to a String to be used when Saving and Loading Player Based Data*/
activeProfile = GameObject.Find("_Managers").GetComponent<ProfileMenuManagement>().activeProfile.ToString();
// If there's scene object data to load
if (ES2.Exists("Profile" + activeProfile + "/" + sceneObjectFile))
{
// Get how many scene objects we need to load, and then try to load each.
// We load scene objects first as created objects may be children of them.
int sceneObjectCount = ES2.Load<int>("Profile" + activeProfile + "/" + sceneObjectFile + "?tag=sceneObjectCount");
for(int i=0; i<sceneObjectCount; i++)
LoadObject(i, "Profile" + activeProfile + "/" + sceneObjectFile);
}
// If there's created objects to load
if (ES2.Exists("Profile" + activeProfile + "/" + createdObjectFile))
{
// Get how many created objects we need to load, and then try to load each.
int createdObjectCount = ES2.Load<int>("Profile" + activeProfile + "/" + createdObjectFile + "?tag=createdObjectCount");
for(int i=0; i<createdObjectCount; i++)
LoadObject(i, "Profile" + activeProfile + "/" + createdObjectFile);
}
}
private void Save()
{
/*Myk: This gets the Active Player Profile number from the Profile Menu Manager and converts
it to a String to be used when Saving and Loading Player Based Data*/
activeProfile = GameObject.Find("_Managers").GetComponent<ProfileMenuManagement>().activeProfile.ToString();
// Save how many scene objects we're saving so we know how many to load.
ES2.Save(UniqueObjectManager.SceneObjects.Length, "Profile" + activeProfile + "/" + sceneObjectFile + "?tag=sceneObjectCount");
// Iterate over each scene object
for(int i=0; i<UniqueObjectManager.SceneObjects.Length; i++)
SaveObject(UniqueObjectManager.SceneObjects[i], i, "Profile" + activeProfile + "/" + sceneObjectFile);
// Save how many created objects we're saving so we know how many to load.
ES2.Save(UniqueObjectManager.CreatedObjects.Count, "Profile" + activeProfile + "/" + createdObjectFile + "?tag=createdObjectCount");
// Iterate over each created object
for(int i=0; i<UniqueObjectManager.CreatedObjects.Count; i++)
SaveObject(UniqueObjectManager.CreatedObjects[i], i, "Profile" + activeProfile + "/" + createdObjectFile);
}
/*
* Saves an Object
* 'i' is the number of the object we are saving.
*/
private void SaveObject(GameObject obj, int i, string file)
{
// Let's get the UniqueID object, as we'll need this.
ES2UniqueID uID = obj.GetComponent<ES2UniqueID>();
//Note that we're appending the 'i' to the end of the path so that
//we know which object each piece of data belongs to.
ES2.Save(uID.id, file+"?tag=uniqueID"+i);
ES2.Save(uID.prefabName, file+"?tag=prefabName"+i);
// Save whether the GameObject this UniqueID is attached to is active or not.
#if UNITY_3_5
ES2.Save(uID.gameObject.active, file+"?tag=active"+i);
#else
ES2.Save(uID.gameObject.activeSelf, file+"?tag=active"+i);
#endif
// You could add many more components here, inlcuding custom components.
// For simplicity, we're only going to save the Transform component.
Transform t = obj.GetComponent<Transform>();
if(t != null)
{
ES2.Save(t, file+"?tag=transform"+i);
// We'll also save the UniqueID of the parent object here, or -1
// string if it doesn't have a parent.
ES2UniqueID parentuID = ES2UniqueID.FindUniqueID(t.parent);
if(parentuID == null)
ES2.Save(-1, file+"?tag=parentID"+i);
else
ES2.Save(parentuID.id, file+"?tag=parentID"+i);
}
}
/*
* Loads an Object
* 'i' is the number of the object we are loading.
*/
private void LoadObject(int i, string file)
{
int uniqueID = ES2.Load<int>(file+"?tag=uniqueID"+i);
string prefabName = ES2.Load<string>(file+"?tag=prefabName"+i);
// Create or get an object based on our loaded id and prefabName
GameObject loadObject;
// If our prefab name is blank, we're loading a scene object.
if(prefabName == "")
loadObject = ES2UniqueID.FindTransform(uniqueID).gameObject;
else
loadObject = UniqueObjectManager.InstantiatePrefab(prefabName);
// Load whether this GameObject is active or not.
#if UNITY_3_5
loadObject.active = ES2.Load<bool>(file+"?tag=active"+i);
#else
loadObject.SetActive(ES2.Load<bool>(file+"?tag=active"+i));
#endif
Transform t = loadObject.GetComponent<Transform>();
if(t != null)
{
// Auto-assigning Load is the best way to load Components.
ES2.Load<Transform>(file+"?tag=transform"+i, t);
// Now we'll get the parent object, if any.
int parentuID = ES2.Load<int>(file+"?tag=parentID"+i);
Transform parent = ES2UniqueID.FindTransform(parentuID);
if(parent != null)
t.parent = parent;
}
}
}
Thanks,
Kind Regards,
Mike
Regards, SW.