Search Unity

Ned some help with save/load between scenes

Discussion in 'Scripting' started by cruising, May 5, 2015.

  1. cruising

    cruising

    Joined:
    Nov 22, 2013
    Posts:
    329
    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.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Xml;
    4. using System.Xml.Serialization;
    5. using System.IO;
    6. using System.Text;
    7.  
    8. public class SavingPosition: MonoBehaviour {
    9.  
    10.     Rect _Save, _Load, _SaveMSG, _LoadMSG;
    11.     bool _ShouldSave, _ShouldLoad,_SwitchSave,_SwitchLoad;
    12.     string _FileLocation,_FileName;
    13.     public GameObject _Player;
    14.     UserData myData;
    15.     string _PlayerName;
    16.     string _data;
    17.    
    18.     Vector3 VPosition;
    19.  
    20.     void Start () {
    21.         _Save=new Rect(10,80,100,20);
    22.         _Load=new Rect(10,100,100,20);
    23.         _SaveMSG=new Rect(10,120,400,40);
    24.         _LoadMSG=new Rect(10,140,400,40);
    25.        
    26.  
    27.         _FileLocation=Application.dataPath;
    28.         _FileName="SaveData.xml";
    29.  
    30.         _PlayerName = "Player";
    31.  
    32.         myData=new UserData();
    33.     }
    34.    
    35.     void Update () {}
    36.    
    37.     void OnGUI()
    38.     {      
    39.         if (GUI.Button(_Load,"Load")) {
    40.            
    41.             GUI.Label(_LoadMSG,"Loading from: "+_FileLocation);
    42.             LoadXML();
    43.             if(_data.ToString() != "")
    44.             {
    45.                 myData = (UserData)DeserializeObject(_data);
    46.                 VPosition=new Vector3(myData._iUser.x,myData._iUser.y,myData._iUser.z);            
    47.                 _Player.transform.position=VPosition;
    48.                 Debug.Log(myData._iUser.name);            
    49.         }
    50.     }      
    51.         if (GUI.Button(_Save,"Save")) {
    52.            
    53.             GUI.Label(_SaveMSG,"Saving to: "+_FileLocation);
    54.             myData._iUser.x=_Player.transform.position.x;
    55.             myData._iUser.y=_Player.transform.position.y;
    56.             myData._iUser.z=_Player.transform.position.z;
    57.             myData._iUser.name=_PlayerName;  
    58.             _data = SerializeObject(myData);
    59.             CreateXML();
    60.             Debug.Log(_data);
    61.         }
    62.     }
    63.     string UTF8ByteArrayToString(byte[] characters)
    64.     {    
    65.         UTF8Encoding encoding = new UTF8Encoding();
    66.         string constructedString = encoding.GetString(characters);
    67.         return (constructedString);
    68.     }
    69.    
    70.     byte[] StringToUTF8ByteArray(string pXmlString)
    71.     {
    72.         UTF8Encoding encoding = new UTF8Encoding();
    73.         byte[] byteArray = encoding.GetBytes(pXmlString);
    74.         return byteArray;
    75.     }
    76.     string SerializeObject(object pObject)
    77.     {
    78.         string XmlizedString = null;
    79.         MemoryStream memoryStream = new MemoryStream();
    80.         XmlSerializer xs = new XmlSerializer(typeof(UserData));
    81.         XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
    82.         xs.Serialize(xmlTextWriter, pObject);
    83.         memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
    84.         XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
    85.         return XmlizedString;
    86.     }
    87.     object DeserializeObject(string pXmlizedString)
    88.     {
    89.         XmlSerializer xs = new XmlSerializer(typeof(UserData));
    90.         MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
    91.         XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
    92.         return xs.Deserialize(memoryStream);
    93.     }
    94.     void CreateXML()
    95.     {
    96.         StreamWriter writer;
    97.         FileInfo t = new FileInfo(_FileLocation+"\\"+ _FileName);
    98.         if(!t.Exists)
    99.         {
    100.             writer = t.CreateText();
    101.         }
    102.         else
    103.         {
    104.             t.Delete();
    105.             writer = t.CreateText();
    106.         }
    107.         writer.Write(_data);
    108.         writer.Close();
    109.         Debug.Log("File written.");
    110.     }
    111.    
    112.     void LoadXML()
    113.     {
    114.         StreamReader r = File.OpenText(_FileLocation+"\\"+ _FileName);
    115.         string _info = r.ReadToEnd();
    116.         r.Close();
    117.         _data=_info;
    118.         Debug.Log("File Read");
    119.     }
    120. }
    121.  
    122. public class UserData
    123. {
    124.     public DemoData _iUser;
    125.     public UserData() { }
    126.     public struct DemoData
    127.     {
    128.         public float x;
    129.         public float y;
    130.         public float z;
    131.         public string name;
    132.     }
    133. }
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    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.
     
  3. cruising

    cruising

    Joined:
    Nov 22, 2013
    Posts:
    329
    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? :O and thats not how i want it to be
     
    Last edited: May 5, 2015
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    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.
     
  5. cruising

    cruising

    Joined:
    Nov 22, 2013
    Posts:
    329
    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
    Code (CSharp):
    1.     void OnGUI()
    2.     {
    3.     if (GUI.Button(_Load,"Load")) {
    4.             GUI.Label(_LoadMSG,"Loading from: "+_FileLocation);
    5.             // Load our UserData into myData
    6.             LoadXML();
    7.             {
    8.             Application.LoadLevel (0);
    9.             {
    10.             if(_data.ToString() != "")
    11.             {
    12.                 myData = (UserData)DeserializeObject(_data);
    13.                 VPosition=new Vector3(myData._iUser.x,myData._iUser.y,myData._iUser.z);          
    14.                 _Player.transform.position=VPosition;
    15.                 Debug.Log(myData._iUser.name);
    16.             }
    17.         }
    18.     }
    19. }
    20.  
    21.         if (GUI.Button(_Save,"Save")) {
    22.          
    23.             GUI.Label(_SaveMSG,"Saving to: "+_FileLocation);
    24.             myData._iUser.x=_Player.transform.position.x;
    25.             myData._iUser.y=_Player.transform.position.y;
    26.             myData._iUser.z=_Player.transform.position.z;
    27.             myData._iUser.name=_PlayerName;
    28.          
    29.             _data = SerializeObject(myData);
    30.             CreateXML();
    31.             Debug.Log(_data);
    32.         }
    33.         Application.LoadLevel (1);
    34. }
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    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
     
  7. cruising

    cruising

    Joined:
    Nov 22, 2013
    Posts:
    329

    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
     
    Last edited: May 5, 2015
  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    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.
     
  9. cruising

    cruising

    Joined:
    Nov 22, 2013
    Posts:
    329

    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?
    Code (CSharp):
    1. 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
    Code (CSharp):
    1. MissingReferenceException: The variable _Player of SavingPosition doesn't exist anymore.
    2. You probably need to reassign the _Player variable of the 'SavingPosition' script in the inspector.
    and i dont realy knows what that means?
     
    Last edited: May 5, 2015
  10. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    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.
     
  11. cruising

    cruising

    Joined:
    Nov 22, 2013
    Posts:
    329
    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"
     
    Last edited: May 5, 2015
  12. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Well, take out the DontDestroyOnLoad calls. I don't believe you need them with the file approach.