Ned some help with save/load between scenes

Hello!

im trying to save a objects pos before loading a other scene, and when you load the main scene again to load and add the saved pos for the object.

I have tried to add Application.LoadLevel(“MyScene”) but i dont know if it does save or load the pos right, it just change scenes and say “file writen” and “file read”

So my question is, where do i put the load code to properly save before load a new scene, and load pos after the main scene is loaded?

Here is the CSharp code for it.

using UnityEngine;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;

public class SavingPosition: MonoBehaviour {

    Rect _Save, _Load, _SaveMSG, _LoadMSG;
    bool _ShouldSave, _ShouldLoad,_SwitchSave,_SwitchLoad;
    string _FileLocation,_FileName;
    public GameObject _Player;
    UserData myData;
    string _PlayerName;
    string _data;
   
    Vector3 VPosition;

    void Start () {
        _Save=new Rect(10,80,100,20);
        _Load=new Rect(10,100,100,20);
        _SaveMSG=new Rect(10,120,400,40);
        _LoadMSG=new Rect(10,140,400,40);
       

        _FileLocation=Application.dataPath;
        _FileName="SaveData.xml";

        _PlayerName = "Player";

        myData=new UserData();
    }
   
    void Update () {}
   
    void OnGUI()
    {       
        if (GUI.Button(_Load,"Load")) {
           
            GUI.Label(_LoadMSG,"Loading from: "+_FileLocation);
            LoadXML();
            if(_data.ToString() != "")
            {
                myData = (UserData)DeserializeObject(_data);
                VPosition=new Vector3(myData._iUser.x,myData._iUser.y,myData._iUser.z);             
                _Player.transform.position=VPosition;
                Debug.Log(myData._iUser.name);            
        }
    }       
        if (GUI.Button(_Save,"Save")) {
           
            GUI.Label(_SaveMSG,"Saving to: "+_FileLocation);
            myData._iUser.x=_Player.transform.position.x;
            myData._iUser.y=_Player.transform.position.y;
            myData._iUser.z=_Player.transform.position.z;
            myData._iUser.name=_PlayerName;   
            _data = SerializeObject(myData);
            CreateXML();
            Debug.Log(_data);
        }
    }
    string UTF8ByteArrayToString(byte[] characters)
    {     
        UTF8Encoding encoding = new UTF8Encoding();
        string constructedString = encoding.GetString(characters);
        return (constructedString);
    }
   
    byte[] StringToUTF8ByteArray(string pXmlString)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        byte[] byteArray = encoding.GetBytes(pXmlString);
        return byteArray;
    }
    string SerializeObject(object pObject)
    {
        string XmlizedString = null;
        MemoryStream memoryStream = new MemoryStream();
        XmlSerializer xs = new XmlSerializer(typeof(UserData));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        xs.Serialize(xmlTextWriter, pObject);
        memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
        XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
        return XmlizedString;
    }
    object DeserializeObject(string pXmlizedString)
    {
        XmlSerializer xs = new XmlSerializer(typeof(UserData));
        MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        return xs.Deserialize(memoryStream);
    }
    void CreateXML()
    {
        StreamWriter writer;
        FileInfo t = new FileInfo(_FileLocation+"\\"+ _FileName);
        if(!t.Exists)
        {
            writer = t.CreateText();
        }
        else
        {
            t.Delete();
            writer = t.CreateText();
        }
        writer.Write(_data);
        writer.Close();
        Debug.Log("File written.");
    }
   
    void LoadXML()
    {
        StreamReader r = File.OpenText(_FileLocation+"\\"+ _FileName);
        string _info = r.ReadToEnd();
        r.Close();
        _data=_info;
        Debug.Log("File Read");
    }
}

public class UserData
{
    public DemoData _iUser;
    public UserData() { }
    public struct DemoData
    {
        public float x;
        public float y;
        public float z;
        public string name;
    }
}

Why are you bringing files into it? Do you really need to save things to disk, or do you only need to get data from one scene to another?

Because in the latter case, there are much easier ways to do it — for example, have an object whose job it is to survive the scene change (because you’ve called DontDestroyOnLoad on it), and put any data you need on that.

I have tried that DontDestroyOnLoad, but it dublicates the objects, and yes i need it on a file or the pos will be deleted next time you start your game? Or im i wrong about that? :open_mouth: and thats not how i want it to be

It doesn’t duplicate the objects if you’re careful about how you do it… but yes, if you also want it to save across quitting and restarting, then you do need to use files.

The save code should be called before you call LoadLevel, and the loading code should be called in Start.

I hope that helps — I’m not entirely clear on what problem you’re encountering.

Yes thats what i tried to do, to save pos before loading a new scene, and load back the scene before loading the saved pos, but nothing happened when i did that, and i guess that because i did some wrong because i dont know where to call LoadLevel before save and load.

When i tried i did something like this

    void OnGUI()
    { 
    if (GUI.Button(_Load,"Load")) {
            GUI.Label(_LoadMSG,"Loading from: "+_FileLocation);
            // Load our UserData into myData
            LoadXML();
            {
            Application.LoadLevel (0);
            {
            if(_data.ToString() != "")
            {
                myData = (UserData)DeserializeObject(_data);
                VPosition=new Vector3(myData._iUser.x,myData._iUser.y,myData._iUser.z);           
                _Player.transform.position=VPosition;
                Debug.Log(myData._iUser.name);
            }
        }
    }
}

        if (GUI.Button(_Save,"Save")) {
         
            GUI.Label(_SaveMSG,"Saving to: "+_FileLocation);
            myData._iUser.x=_Player.transform.position.x;
            myData._iUser.y=_Player.transform.position.y;
            myData._iUser.z=_Player.transform.position.z;
            myData._iUser.name=_PlayerName; 
         
            _data = SerializeObject(myData);
            CreateXML();
            Debug.Log(_data);
        }
        Application.LoadLevel (1); 
}

I don’t understand your code here, partly because it’s not indented properly so it’s really hard to see what lines up with what.

But I can see that you’re calling LoadXML right before LoadLevel. There’s no point in that; LoadLevel means “throw out everything in memory (except objects with DontDestroyOnLoad) and load a new scene.” I also see that you’re doing stuff after calling LoadLevel; not much point in that either. Think of LoadLevel as “quit.”

It also appears that you’re drawing a Save button, and when it’s clicked, saving your data… but whether it’s clicked or not, you’re calling Application.LoadLevel. Like, on every frame, unless I’ve grossly misunderstood all those curly braces. That doesn’t make any sense either.

Finally, I don’t understand how this script is at all what I suggested:

This code you’ve shown is all in OnGUI. The loading code should be in Start (only). The saving code and LoadLevel (which you should think of as “quit”) should be together, in OnGUI if you like, but in the very same if-block. And that’s it. You shouldn’t be calling LoadLevel in two places; you shouldn’t attempt to do anything else after calling LoadLevel; you shouldn’t have any loading code in OnGUI.

Just save your data before you call LoadLevel, and load your data in Start, and you should be good.

HTH,

  • Joe

The code i just posted makes the buttons to save and load pos only, if you remove the LoadLevel part.
I think i understand what you mean here, but could you please show me how you would do to point me in right direction?

Should i call a separate function for the LoadLevel when clicking a button instead?
Im a bit confused at moment.

EDIT:
i have moved the load file code part to the start and it loads the last saved pos when starting game, i just need to make it so it only do that on lvl 0 or else i will end up at the same pos on the new scene since i only want to load a pos on the main lvl “0” and to make is save the pos before loading a scene, but how that is done im not sure about

If I understand you correctly, you only want to run the load code in level 0, and not in any other scene?

In that case, you can either put the loading code on a component that is simply not present in any other scene, or you can add an “if” block that looks at the current level name.

Yes thats correct, i making a big space. I have a ship with a bridge that you need to load a scene for to visit, and when you leave the “ship view” it should save the pos if the ship object.

And when you leave the ships bridge back to “ship view” it should load the last saved pos, i hope i explaned so you understand me right.

EDIT:

is this right?

if(Application.loadedLevelName == "scene0") {

EDIT2:

I have succeeded to load current saved pos on starting game, load the bridge (scene1) and load back to (scene0) with the current saved pos, however…when i then trying to load the bridge scene again it says

MissingReferenceException: The variable _Player of SavingPosition doesn't exist anymore.
You probably need to reassign the _Player variable of the 'SavingPosition' script in the inspector.

and i dont realy knows what that means?

Looks like you’re on the right track! I’m not entirely sure what that error means either. Are you still calling DontDestroyOnLoad on something? That’s probably not necessary, since you’re using file I/O to get your data from scene to scene.

If you’re not calling that, then there shouldn’t be any difference between loading scene1 the first time, and loading it the second time. So I don’t know why you would get an error the second time.

Yeah i hope i am.

I have dont destry on following
1: start
2: when klick on “exit bridge” (loading scene 0)
3: when klick on “visit bridge” (loading scene 1)

Or else i getting that error if i try the first time, i have no idea why i need it twice when i have it on “start”

Well, take out the DontDestroyOnLoad calls. I don’t believe you need them with the file approach.