Advertisement
Guest User

Save / Load System Unity - 2D Game Development in Unity 5.6

a guest
Jun 25th, 2017
3,477
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.11 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Xml;
  5. using System.Xml.Serialization;
  6. using UnityEngine;
  7. using UnityEngine.SceneManagement;
  8.  
  9. /// <summary>
  10. /// Class for handling persistent game data
  11. /// </summary>
  12. public class GameControl : MonoBehaviour
  13. {
  14.     #region Public Fields
  15.  
  16.     public static GameControl Instance;
  17.     public GameData gameData = new GameData();
  18.     public Scene openScene;
  19.  
  20.     private string savePath;
  21.     public string SavePath
  22.     {
  23.         get
  24.         {
  25.             if (savePath != null)
  26.                 return savePath;
  27.             else
  28.             {
  29.                 savePath = Application.persistentDataPath + "/SavedGames/";
  30.                 return savePath;
  31.             }
  32.         }
  33.     }
  34.  
  35.     #endregion Public Fields
  36.  
  37.     #region Private Fields
  38.  
  39.     private const string FILE_EXTENSION = ".xml";
  40.  
  41.     // Save Load Data
  42.     private string saveFile;
  43.  
  44.     #endregion Private Fields
  45.  
  46.     #region Public Methods
  47.  
  48.     /// <summary>
  49.     /// Deletes the save file if it exists and errors out otherwise.
  50.     /// </summary>
  51.     /// <param name="saveFile"></param>
  52.     public void DeleteSaveFile(string saveFile)
  53.     {
  54.         if (File.Exists(SavePath + saveFile + FILE_EXTENSION))
  55.         {
  56.             File.Delete(SavePath + saveFile + FILE_EXTENSION);
  57.         }
  58.         else
  59.         {
  60.             Debug.LogError("Failed to delete non existant file " + SavePath + saveFile + FILE_EXTENSION);
  61.         }
  62.     }
  63.  
  64.     /// <summary>
  65.     /// Checks if the save file exists in the file system
  66.     /// </summary>
  67.     /// <param name="testFileName"></param>
  68.     /// <returns>True if it exists and false otherwise</returns>
  69.     public bool DoesFileExist(string testFileName)
  70.     {
  71.         foreach (GameData data in GetAllSaveFiles())
  72.         {
  73.             if (data.lastSaveFile == testFileName)
  74.             {
  75.                 return true;
  76.             }
  77.         }
  78.  
  79.         return false;
  80.     }
  81.  
  82.     /// <summary>
  83.     /// Create a new file name, check for existing files of same player name
  84.     /// </summary>
  85.     /// <returns></returns>
  86.     public string GenerateNewSaveName()
  87.     {
  88.         int attempt = 0;
  89.         string newSaveName = "";
  90.  
  91.         while (newSaveName == "")
  92.         {
  93.             // Save Name is Player Name
  94.             string checkString = gameData.playerName;
  95.  
  96.             // Add a number if original already taken
  97.             if (attempt != 0) checkString += attempt;
  98.  
  99.             if (!File.Exists(SavePath + checkString))
  100.             {
  101.                 // Make the check string the new file name
  102.                 newSaveName = checkString;
  103.             }
  104.  
  105.             attempt++;
  106.         }
  107.  
  108.         return newSaveName;
  109.     }
  110.  
  111.     /// <summary>
  112.     /// Gets a list of all save files in the save directory.
  113.     /// </summary>
  114.     /// <returns></returns>
  115.     public List<GameData> GetAllSaveFiles()
  116.     {
  117.         List<GameData> allSaves = new List<GameData>();
  118.  
  119.         // Check Save Path
  120.         foreach (string fileName in Directory.GetFiles(SavePath))
  121.         {
  122.             // Get Player Data for Each File
  123.             allSaves.Add(GetSaveFile(fileName));
  124.         }
  125.  
  126.         return allSaves;
  127.     }
  128.  
  129.     /// <summary>
  130.     /// Finds the value associated with the flag
  131.     /// </summary>
  132.     /// <param name="flagName"></param>
  133.     /// <returns></returns>
  134.     public int GetFlag(string flagName)
  135.     {
  136.         GameFlag flag = gameData.gameFlags.Find(x => x.flag == flagName);
  137.  
  138.         // Create Non-existant flags but default to 0
  139.         if (flag == null)
  140.         {
  141.             SetFlag(flagName, 0);
  142.             return 0;
  143.         }
  144.  
  145.         return flag.value;
  146.     }
  147.  
  148.     /// <summary>
  149.     /// Checks if a particular level has been cleared yet or not
  150.     /// </summary>
  151.     /// <param name="level">Level to check</param>
  152.     /// <returns>True if cleared and false otherwise</returns>
  153.     public bool GetLevelCleared(int level)
  154.     {
  155.         return GetFlag("level" + level + "cleared") == 1 ? true : false;
  156.     }
  157.  
  158.     /// <summary>
  159.     /// Load game data from file for active use
  160.     /// </summary>
  161.     /// <param name="gameName"></param>
  162.     /// <returns></returns>
  163.     public void LoadGame(string gameName)
  164.     {
  165.         CheckDirectory();
  166.  
  167.         // Assemble path to file to load game from
  168.         String fullFilePath = SavePath + gameName + FILE_EXTENSION;
  169.        
  170.         if (File.Exists(fullFilePath))
  171.         {
  172.             // Put it into a file
  173.             Debug.Log("Deserializing " + fullFilePath);
  174.  
  175.             FileStream fs = File.Open(fullFilePath, FileMode.Open);
  176.  
  177.             // Deserialize the XML Save File (Using XmlSerializer instead of BinarySerializer)
  178.             XmlSerializer xmlSerializer = new XmlSerializer(typeof(GameData));
  179.             XmlReader reader = XmlReader.Create(fs);
  180.             gameData = xmlSerializer.Deserialize(reader) as GameData;
  181.             fs.Close();
  182.  
  183.             // Loads the scene from which the game was saved
  184.             SceneManager.LoadSceneAsync(gameData.savedScene, LoadSceneMode.Single);
  185.         }
  186.         else
  187.         {
  188.             Debug.Log("Failed to save to file " + fullFilePath);
  189.         }
  190.     }
  191.  
  192.     /// <summary>
  193.     /// Save all game data to file
  194.     /// </summary>
  195.     /// <param name="saveFile"></param>
  196.     public void SaveGame(string saveFile)
  197.     {
  198.         CheckDirectory();
  199.  
  200.         // Update saveFile name
  201.         if (saveFile == null)
  202.         {
  203.             saveFile = GenerateNewSaveName();
  204.         }
  205.  
  206.         this.saveFile = saveFile;
  207.  
  208.         // FileStream fs = File.Create(GameDic.Instance.SavePath + saveFile);
  209.  
  210.         UpdateSaveData(saveFile);
  211.  
  212.         string fullSavePath = SavePath + saveFile + FILE_EXTENSION;
  213.  
  214.         FileStream fs;
  215.  
  216.         // Create a file or open an old one up for writing to
  217.         if (!File.Exists(fullSavePath))
  218.         {
  219.             fs = File.Create(fullSavePath);
  220.         }
  221.         else
  222.         {
  223.             fs = File.OpenWrite(fullSavePath);
  224.         }
  225.  
  226.         XmlSerializer serializer = new XmlSerializer(typeof(GameData));
  227.         TextWriter textWriter = new StreamWriter(fs);
  228.         serializer.Serialize(textWriter, gameData);
  229.         fs.Close();
  230.  
  231.         Debug.Log("Game Saved to " + fullSavePath);
  232.     }
  233.  
  234.     /// <summary>
  235.     /// Set Current Save Related Information on gameData
  236.     /// </summary>
  237.     /// <param name="saveFile"></param>
  238.     private void UpdateSaveData(string saveFile)
  239.     {
  240.         gameData.lastSaveFile = saveFile;
  241.         gameData.lastSaveTime = DateTime.Now.ToBinary();
  242.         gameData.savedScene = SceneManager.GetActiveScene().name;
  243.     }
  244.  
  245.     // For flag storing and getting
  246.     public void SetFlag(string flagName, int value)
  247.     {
  248.         // Overwrite Old Key/Values
  249.         GameFlag oldFlag = gameData.gameFlags.Find(x => x.flag == flagName);
  250.  
  251.         // Either update the value or add a new one if it does not exist
  252.         if (oldFlag != null)
  253.         {
  254.             oldFlag.value = value;
  255.         }
  256.         else
  257.         {
  258.             // Does not exist in list
  259.             gameData.gameFlags.Add(new GameFlag(flagName, value));
  260.         }
  261.     }
  262.  
  263.     #endregion Public Methods
  264.  
  265.     #region Private Methods
  266.  
  267.     /// <summary>
  268.     /// Checks if the file has not yet been created
  269.     /// </summary>
  270.     /// <param name="saveFile"></param>
  271.     /// <returns></returns>
  272.     private bool IsNewFile(string saveFile)
  273.     {
  274.         return !File.Exists(SavePath + saveFile + FILE_EXTENSION);
  275.     }
  276.  
  277.     /// <summary>
  278.     /// Initialization
  279.     /// </summary>
  280.     private void Awake()
  281.     {
  282.         //Check if instance already exists
  283.         if (Instance == null)
  284.         {
  285.             //if not, set instance to this
  286.             Instance = this;
  287.  
  288.             // Find objects on level - necessary to call directly for first load
  289.             SceneManager.sceneLoaded += OnSceneLoaded;
  290.             openScene = SceneManager.GetActiveScene();
  291.         }
  292.  
  293.         //If instance already exists and it's not this:
  294.         else if (Instance != this)
  295.  
  296.             //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
  297.             Destroy(gameObject);
  298.  
  299.         // Sets this to not be destroyed when reloading scene
  300.         DontDestroyOnLoad(gameObject);
  301.     }
  302.  
  303.     /// <summary>
  304.     /// Checks to see if the SavePath directory exists and creates a new one of it does not.
  305.     /// </summary>
  306.     private void CheckDirectory()
  307.     {
  308.         // Check if directory exists, if not create it
  309.         if (!Directory.Exists(SavePath))
  310.         {
  311.             Directory.CreateDirectory(SavePath);
  312.         }
  313.     }
  314.  
  315.     /// <summary>
  316.     /// Retrieves the data stored inside of a save file
  317.     /// </summary>
  318.     /// <param name="fullFilePath"></param>
  319.     /// <returns></returns>
  320.     private GameData GetSaveFile(string fullFilePath)
  321.     {
  322.         if (File.Exists(fullFilePath))
  323.         {
  324.             // Old Binary Formmater Method BinaryFormatter bf = new BinaryFormatter(); FileStream
  325.             // fs = File.Open(fullFilePath, FileMode.Open);
  326.  
  327.             // Put it into a file PlayerData data = (PlayerData)bf.Deserialize(fs);
  328.  
  329.             // fs.Close();
  330.  
  331.             // XML SERIALIZER TEST INSTEAD OF BINARYFORMATTER
  332.             FileStream fs = File.Open(fullFilePath, FileMode.Open);
  333.  
  334.             XmlSerializer xmlSerializer = new XmlSerializer(typeof(GameData));
  335.             XmlReader reader = XmlReader.Create(fs);
  336.             GameData data = xmlSerializer.Deserialize(reader) as GameData;
  337.             fs.Close();
  338.  
  339.             return data;
  340.         }
  341.         else
  342.         {
  343.             Debug.LogError("Failed to save to file " + fullFilePath);
  344.             return null;
  345.         }
  346.     }
  347.  
  348.     /// <summary>
  349.     /// Make sure that the save / load directory exists.
  350.     /// </summary>
  351.     /// <param name="scene"></param>
  352.     /// <param name="mode"></param>
  353.     private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
  354.     {
  355.         CheckDirectory();
  356.     }
  357.  
  358.     #endregion Private Methods
  359. }
  360.  
  361. [Serializable]
  362. public class GameFlag
  363. {
  364.     #region Public Fields
  365.  
  366.     public string flag;
  367.     public int value;
  368.  
  369.     #endregion Public Fields
  370.  
  371.     #region Public Constructors
  372.  
  373.     public GameFlag()
  374.     {
  375.     }
  376.  
  377.     public GameFlag(string flag, int value)
  378.     {
  379.         this.flag = flag;
  380.         this.value = value;
  381.     }
  382.  
  383.     #endregion Public Constructors
  384. }
  385.  
  386. [Serializable]
  387. public class GameData
  388. {
  389.     #region Public Fields
  390.  
  391.     public int currentChapter;
  392.  
  393.     public List<GameFlag> gameFlags;
  394.  
  395.     public float health;
  396.  
  397.     public string playerName;
  398.  
  399.     // Needs properties to access
  400.     [NonSerialized]
  401.     public Vector3 playerPosition;
  402.  
  403.     public string lastSaveFile;
  404.  
  405.     public long lastSaveTime;
  406.  
  407.     public string savedScene;
  408.    
  409.     public int upgradePoints = 0;
  410.  
  411.     public int upgradePointsSpent = 0;
  412.  
  413.     #endregion Public Fields
  414.  
  415.     #region Public Constructors
  416.  
  417.     /// <summary>
  418.     /// Default Constructor for New Game - Contains Starting Stats
  419.     /// </summary>
  420.     public GameData()
  421.     {
  422.         playerPosition = Vector3.zero;
  423.         health = 100;
  424.         playerName = "Jill";
  425.         upgradePoints = 0;
  426.         upgradePointsSpent = 0;
  427.         currentChapter = 1;
  428.         savedScene = "";
  429.         gameFlags = new List<GameFlag>();
  430.     }
  431.  
  432.     #endregion Public Constructors
  433.  
  434.     #region Public Properties
  435.  
  436.     // Can't serialize a vector so needs to be broken down into 3 properties
  437.     public float PlayerPositionX
  438.     {
  439.         get
  440.         {
  441.             return playerPosition.x;
  442.         }
  443.         set
  444.         {
  445.             playerPosition.x = value;
  446.         }
  447.     }
  448.  
  449.     public float PlayerPositionY
  450.     {
  451.         get
  452.         {
  453.             return playerPosition.y;
  454.         }
  455.         set
  456.         {
  457.             playerPosition.y = value;
  458.         }
  459.     }
  460.  
  461.     public float PlayerPositionZ
  462.     {
  463.         get
  464.         {
  465.             return playerPosition.z;
  466.         }
  467.         set
  468.         {
  469.             playerPosition.z = value;
  470.         }
  471.     }
  472.  
  473.     #endregion Public Properties
  474. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement