Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Saving game (serialization, Binary) [RESOLVED]

Discussion in 'Scripting' started by Zaine7673, Mar 14, 2018.

  1. Zaine7673

    Zaine7673

    Joined:
    Feb 15, 2018
    Posts:
    238
    Hi all,

    I've spent the whole day trying to understand this and there is just one part i can't seem to figure out no matter what i read or how many videos i watch.

    So I have a script for saving a game (one thing at a time)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.IO;
    7.  
    8. public class SaveLoadManager:MonoBehaviour{
    9.     void Sart(){
    10.      
    11.     }
    12.  
    13.     public void save(){
    14.         BinaryFormatter bf = new BinaryFormatter();
    15.         FileStream file = File.Open(Application.persistentDataPath + "/save.dat", FileMode.OpenOrCreate);
    16.         SaveData saveData = new SaveData ();
    17.         bf.Serialize(file, saveData);
    18.         file.Close();
    19.     }
    20. }
    21.  
    22. [Serializable]
    23. public class SaveData{
    24.     public int currentLevel;
    25. }
    And on another script i am trying to update the currentLevel in the SaveData class and then call the save method in the SaveLoadManager class. like

    Code (CSharp):
    1. public class Example : MonoBehaviour {
    2. public SaveLoadManager saveLoadManager;
    3.     public SaveData saveData;
    4.  
    5. void Start(){
    6. saveData.currentLevel = 20;
    7. saveLoadManager.save ();
    8. }
    9. }
    now I am fairly new to c# (coming from a web dev - javascript, PHP background)
    I am expecting the currentLevel to be updated and then saved using the save method but it doesnt seem to work. The currentLevel stays at 0 on the SaveLoadManager class but it updated on the other script. What does work is if I do something like

    Code (CSharp):
    1. public void save(){
    2.         BinaryFormatter bf = new BinaryFormatter();
    3.         FileStream file = File.Open(Application.persistentDataPath + "/save.dat", FileMode.OpenOrCreate);
    4.         SaveData saveData = new SaveData ();
    5.         [B]saveData.currentlLevel = 20;[/B]
    6.         bf.Serialize(file, saveData);
    7.         file.Close();
    8.     }
    but this is not what I want. Can someone please help me understand where I am going wrong? I'm sure it's something so small that I'm not understanding
     
  2. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
  3. Zaine7673

    Zaine7673

    Joined:
    Feb 15, 2018
    Posts:
    238
    Thanks buddy, I've seen/read most of these already - the ones I haven't seen/read I took the time to go over but i still have no luck in reading/writing that value :-(
     
  4. Zaine7673

    Zaine7673

    Joined:
    Feb 15, 2018
    Posts:
    238
    okay so I've managed to get it to work (thanks to one of the videos I watched that you referred me to)
    It was a small tweak but made all the difference and allowed me to do what i wanted so I'm going to put this up here for any other noobs who get as confused as i did lol

    This is the SaveLoadClass - note that the difference is I have marked the Save method and the currentLevel variable as static and removed monobehaviour (just so i don't need a empty game object in my hierarchy)
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.IO;
    7.  
    8. public class SaveLoadManager{
    9.     void Sart(){
    10.      
    11.     }
    12.  
    13.     public static void Save(){
    14.         BinaryFormatter bf = new BinaryFormatter();
    15.         FileStream file = File.Open(Application.persistentDataPath + "/save.dat", FileMode.OpenOrCreate);
    16.         SaveData saveData = new SaveData ();
    17.         bf.Serialize(file, saveData);
    18.         file.Close();
    19.     }
    20. }
    21.  
    22. [Serializable]
    23. public class SaveData{
    24.     public static int currentLevel = 20;
    25. }
    26.  
    Now I can set the variable from any other script and call the Save method to save the updated values.

    Code (CSharp):
    1. SaveData.currentLevel = 50;
    2.         SaveLoadManager.Save ();
    I really hope this helps anyone who get stuck trying to do this.

    How do I mark this thread as resolved?
     
  5. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    That's great and yes it's always good to write down your solutions because then it helps the total beginners out who are just learning this stuff, it's very surprising to me how little up to date information there is on serialization which is why I made that thread to ask people for information.

    I think it's to do with how big and complicated the subject is, the professionals and experienced types are very reluctant to talk about it because of that.
     
    RealMaxwell likes this.
  6. Zaine7673

    Zaine7673

    Joined:
    Feb 15, 2018
    Posts:
    238
    I think you may be right. There are plenty of tutorials out there but to somebody who has just started, it seems a little under-explained. writing the file is not difficult, it's handling the data that's the hardest to get your head around. Especially as I've come from developing in PHP where it isn't as strict with data types and so on.

    So now I've managed to write the data, i can't seem to restore the data after the file has been loaded and read LOL

    Ah man.

    thanks for all your help buddy :)
     
  7. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    Someone else will come along and help you with that bit I'm sure, alternatively you'll just have to tweak bits of code until it works.
     
  8. Zaine7673

    Zaine7673

    Joined:
    Feb 15, 2018
    Posts:
    238
    All done bro :) it seems i couldn't retrieve the saved variable as it was static and there can only be one. I needed them to be static so they can be dynamically changed via other scripts. I just worked around it and made another class that would take that data and store it in non-static variables then on load would restore them to the static ones in the other class.

    For anyone who is looking for something to re-use each time to store simple data:

    Put this into a script and change the bold parts to whatever you want or just add if you want to store more data. but you must add whatever static variable you have in SaveData to SerializableSaveData (including inside the RestoreSaveData Method)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.IO;
    7.  
    8. public class SaveLoadManager{
    9.     void Sart(){
    10.        
    11.     }
    12.  
    13.     public static void Save(){
    14.         BinaryFormatter bf = new BinaryFormatter();
    15.         FileStream file = File.Open(Application.persistentDataPath + "/save.dat", FileMode.OpenOrCreate);
    16.         SerializableSaveData serializableSaveData = new SerializableSaveData ();
    17.         bf.Serialize(file, serializableSaveData);
    18.         file.Close();
    19.         //Debug.Log (SaveData.currentLevel);
    20.     }
    21.  
    22.     public static bool Load(){
    23.         if (File.Exists (Application.persistentDataPath + "/save.dat")) {
    24.             BinaryFormatter bf = new BinaryFormatter ();
    25.             FileStream file = File.Open(Application.persistentDataPath + "/save.dat", FileMode.Open);
    26.             SerializableSaveData serializableSaveData = (SerializableSaveData)bf.Deserialize(file);
    27.             file.Close();
    28.             serializableSaveData.RestoreSaveData ();
    29.             Debug.Log (SaveData.currentLevel);
    30.             return(true);
    31.         } else {
    32.             return(false);
    33.         }
    34.     }
    35. }
    36.    
    37. public class SaveData{
    38.     public static [B]int currentLevel[/B];
    39. }
    40.  
    41. [Serializable]
    42. public class SerializableSaveData{
    43.     private [B]int currentLevel[/B] = SaveData.[B]currentLevel[/B];
    44.  
    45.     public void RestoreSaveData(){
    46.         SaveData.[B]currentLevel[/B] = [B]currentLevel[/B];
    47.     }
    48. }
    And then just update each static variable and call the Save method like this

    Code (CSharp):
    1. SaveData.currentLevel = 50;
    2.         SaveLoadManager.Save ();
    Or to load the data and retrieve just call the Load method and read the static variables from SaveData like this

    Code (CSharp):
    1. bool val = SaveLoadManager.Load ();
    2.         if (val) {
    3.             Debug.Log (SaveData.currentLevel);
    4.         }
    It seems to be working fine for me so far. Not sure how secure this is. Maybe someone else can tell us.
     
  9. stannesi

    stannesi

    Joined:
    Apr 18, 2015
    Posts:
    2
    try using
    Code (CSharp):
    1. File.Create
    to save
     
  10. unity_27hrishik

    unity_27hrishik

    Joined:
    Feb 18, 2018
    Posts:
    2
    It's been quite a long time. But still for future viewers, The only problem with the first script is the save function :
    it's creating a new instance of save data and its serializing the temporary instance of save data.
    whereas, the actual instance in Example is just unused.
    Solution: to just pass the instance into the function like:
    Code (CSharp):
    1. public static void Save(SaveData saveData){
    2.         BinaryFormatter bf = new BinaryFormatter();
    3.         FileStream file = File.Open(Application.persistentDataPath + "/save.dat", FileMode.OpenOrCreate);
    4.         //SaveData saveData = new SaveData (); not needed as the object is being passed
    5.         bf.Serialize(file, saveData);
    6.         file.Close();
    7.     }
    and the example script will be modified as
    Code (CSharp):
    1. public class Example : MonoBehaviour {
    2. public SaveLoadManager saveLoadManager;
    3.     public SaveData saveData;
    4. void Start(){
    5. saveData.currentLevel = 20;
    6. saveLoadManager.save (saveData);
    7. }
    8. }
     
  11. Zaine7673

    Zaine7673

    Joined:
    Feb 15, 2018
    Posts:
    238
    its been a long time indeed but im always curious as to how i can write more elegant code. Its been working for me so far but I like your edits better so i will try it and if all is okay then i shall come back to thank you and send you a digital handshake