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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How to store multiple variable type in one "list" to save and load them easily ?

Discussion in 'Scripting' started by Bakudan, Apr 5, 2015.

  1. Bakudan

    Bakudan

    Joined:
    Mar 29, 2015
    Posts:
    16
    Hello,
    Since i'm a beginner in C# i got some issue with the way to do thing, even if i completely got the logic^^.

    I'm building a game like a "Heroe Clicker / Tap Titan", which is perfecltly working so far, but i am facing a wall to easily save all my variables and get them without writing dozens of lines for each.

    My player class is currently something like this :
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. [System.Serializable]
    7.  
    8. public class Player{
    9.     public static Player current;
    10.     public static float Life = 500;
    11.     public static float LifeLvl = 1;
    12.     public static float LifeAdd = 50;
    13.     public static float afk_death_timer = 2;
    14.     public static float Strengh = 60;
    15.     public static float StrenghLvl = 1;
    16.     public static float StrenghAdd = 15;
    17. .... bool
    18. ...int
    19. .... string
    20. .... douzens of other stats
    (Its all static because i'm not gonna have other Characters so i don't see the point to instantiate this multiple times, maybe i'm wrong ?)
    Plus other game variables in another class such as the time played, UI buttons and Perks activated ingame before saving....

    But currently to save them i have to manually add them one by one in Playerprefs and get them One by one in the Loading function. Which make each of this fonction close to 200 code lines.

    I though i can put them in a List like this : Player List[string name, string type, string value]
    (Life,int,500), (LiveActivation, bool, true)

    And then save and get Player[] in one line on the save and load function ?
    But then i will have to convert each one according to its type i'm not sure how.

    something like this ? : Life = Player[Life].value.ToInt if if type is Int, .ToFloat if type is float.... ?


    I also hearded about a method to save a complete Class from serialization, so i tried this :

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using System.IO;
    6.  
    7. public static class SaveLoad {
    8.  
    9.     public static List<Player> savedGames = new List<Player>();
    10.  
    11.     //it's static so we can call it from anywhere
    12.     public static void Save() {
    13.         SaveLoad.savedGames.Add(Player.current);
    14.         BinaryFormatter bf = new BinaryFormatter();
    15.         //Application.persistentDataPath is a string, so if you wanted you can put that into debug.log if you want to know where save games are located
    16.         FileStream file = File.Create (Application.persistentDataPath + "/savedGames.gd"); //you can call it anything you want
    17.         bf.Serialize(file, SaveLoad.savedGames);
    18.         file.Close();
    19.         Debug.Log (Application.persistentDataPath);
    20.         Debug.Log (savedGames);
    21.  
    22.     }
    23.  
    24.     public static void Load() {
    25.         if(File.Exists(Application.persistentDataPath + "/savedGames.gd")) {
    26.             BinaryFormatter bf = new BinaryFormatter();
    27.             FileStream file = File.Open(Application.persistentDataPath + "/savedGames.gd", FileMode.Open);
    28.             SaveLoad.savedGames = (List<Player>)bf.Deserialize(file);
    29.             file.Close();
    30.             Debug.Log (savedGames);
    31.         }
    32.     }
    33. }
    But the result was an almost empty file in the save folder, with just th ename of the class apparently saved...

    I would really appreciate if someone can show me an easy way for this.
    Thanks.



    EDIT :
    I found another solution which didn't work either :
    Code (CSharp):
    1.     public void SaveGame () {
    2.         Player player = new Player{};
    3.         Serializer.Save<Player>("save.txt", player);
    4.         Debug.Log ("Saved");
    With Serializer script as :
    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. using UnityEngine;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Runtime.Serialization.Formatters.Binary;
    7.  
    8. public class Serializer
    9. {
    10.     public static T Load<T>(string filename) where T: class
    11.     {
    12.         if (File.Exists(filename))
    13.         {
    14.             try
    15.             {
    16.                 using (Stream stream = File.OpenRead(filename))
    17.                 {
    18.                     BinaryFormatter formatter = new BinaryFormatter();
    19.                     return formatter.Deserialize(stream) as T;
    20.                 }
    21.             }
    22.             catch (Exception e)
    23.             {
    24.                 Debug.Log(e.Message);
    25.             }
    26.         }
    27.         return default(T);
    28.     }
    29.  
    30.     public static void Save<T>(string filename, T data) where T: class
    31.     {
    32.         using (Stream stream = File.OpenWrite(filename))
    33.         {  
    34.             BinaryFormatter formatter = new BinaryFormatter();
    35.             formatter.Serialize(stream, data);
    36.         }
    37.     }
    38. }
    39.  
    In the end i get the same result as previoulsy, is save a .txt file with only the Class name inside. Look's like i'm missing something.
     
    Last edited: Apr 5, 2015
  2. Bakudan

    Bakudan

    Joined:
    Mar 29, 2015
    Posts:
    16
    I found the probleme about the Serialize option, it was saving an empty class because all my variables were static, so i just passed all of them public and make this change :
    Code (CSharp):
    1. public class save_load : MonoBehaviour {
    2.  
    3.  
    4.  
    5.     public Player player_copy;
    6.     private Player player_saver;
    7.     // Use this for initialization
    8.     void Start () {
    9.         player_copy.lifetest8 = "Mewtwo";
    10.         player_saver = player_copy;
    11.         Debug.Log (player_saver.lifetest8);
    12.         player_copy.lifetest8 = "Raichu";
    13.         Debug.Log (player_saver.lifetest8);
    14.     }
    15.  
    16.     public void LoadGame (){
    17.         Player newSimpleClass = Serializer.Load<Player>("save.txt");
    18.         Debug.Log (newSimpleClass.lifetest8);
    19.     }
    20.  
    21.     public void SaveGame () {
    22.         Serializer.Save<Player>("save.txt", player_saver);
    23.         Debug.Log (player_saver);
    24.         Debug.Log ("Saved");
    25. }
    Now i can use my "public" class Player without static variables in others script, modifing the copy also modifie the saver one, and the save/load method are working, its perfect ^^.
     
  3. zoran404

    zoran404

    Joined:
    Jan 11, 2015
    Posts:
    520
    Well yeah. The static variables can't change so there is no point in saving them.
    Plus you don't need an object reference to use the static variables.
     
  4. Korno

    Korno

    Joined:
    Oct 26, 2014
    Posts:
    518
    Not entirely true, static variables can change just that they are not unique to one instance of a class but the class itself. You don't need an instance of the object to access them. Constants are variables that can`t change value.

    Most serializers I have played with ignore static variables when they serialize a class. Although there is probably a way to force it to serialize them.
     
  5. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,739
    Singalton just make a static variable that is a reference to 1 object of the same class
     
  6. zoran404

    zoran404

    Joined:
    Jan 11, 2015
    Posts:
    520
    I confused static and const, how stupid of me.
     
  7. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    This. Don't make your player class static. While static members can change they should generally be thought of as immutable. So instead, use a regular POCO (plain old clr object a.k.a just a regular class) for your player and create some kind of Manager class if you want to have a static reference to it.