Briefly introduce several methods of storing and reading data in Unity!

Briefly introduce several methods of storing and reading data in Unity!

There are several main ways to store and read game data in Unity:

  • Use local persistence class PlayerPrefs
  • Use binary methods to serialize and deserialize (Serialize, Deserialize)
  • Use Json method
  • Use XML method.

Below, we will use these four methods to store and read files through a simple example.


To achieve the goal:
   Make a simple scoring system, press the S key to increase the score by one, and press the B key to decrease the blood volume by one. Make a save button in the UI design to save data, and then make a load button to load the data saved in the previous game into the scene.

Building the scene: Since it is relatively simple, I will not go into details one by one. Just go to the picture above:
Insert image description here
The main thing is to talk about the structure in the Hierarchy panel in unity, because I am worried that some friends will get it confused.
Insert image description here
First, create a Canvas. The two images below it are the backgrounds of blood volume and score (irrelevant). CurrentBloodVolume is a Text used to display the current blood volume. CurrentScore is also a Text used to display the current score. save is a button, used to save, load is also a button, used to load, GameManager is an empty object, used to mount the GameManager script, this script mainly contains various methods, game logic, ScoreAndBlood is also an empty object, used to Mount the ScoreAndBlood script, which contains code for adding points and reducing blood.

Script creation: Create a Date script. This script does not need to inherit MonoBehaviour, because this script is used for serialization and deserialization. You need to add the data that the game needs to save to this class. When you finally want to read the file, you also need to add it from Read saved data in this class. We also need a class ScoreAndBlood to add points and reduce blood, and finally a game main logic class GameManager.

Let’s give some necessary pieces of code at the beginning:
codes for adding points and reducing blood:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ScoreAndBlood : MonoBehaviour
{
    
    
    public static ScoreAndBlood _instance;

    public Text currentBloodVolume;
    public Text currentScore;

    public int BloodVolume = 100;
    public int Score = 0;

    private bool isCanReduce = true;


    private void Awake()
    {
    
    
        _instance = this;
    }
    private void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.B) && isCanReduce)
        {
    
    
            BloodVolume--;
            currentBloodVolume.text = BloodVolume.ToString();
            if (BloodVolume < 0)
            {
    
    
                isCanReduce = false;
            }
        }
        if (Input.GetKeyDown(KeyCode.S))
        {
    
    
            Score++;
            currentScore.text = Score.ToString();
        }
    }
}

Script Date that needs to store and read game data:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class Date
{
    
    
    public int BloodVolume;
    public int Score;
}

Methods to store data in Date and read data from Date in GameManager script

  //创建Data对象,并向其中添加游戏需要保存的数据
    private Date GetGameDate()
    {
    
    
        Date date = new Date();
        date.BloodVolume = ScoreAndBlood._instance.BloodVolume;
        date.Score = ScoreAndBlood._instance.Score;

        return date; 
    }
    //向游戏中加载Date中保存的数据的方法
    private void SetGameDate( Date date)
    {
    
    
        ScoreAndBlood._instance.currentBloodVolume.text = date.BloodVolume.ToString();
        ScoreAndBlood._instance.currentScore.text = date.Score.ToString();
    }

(1) PlayerPrefs
PlayerPrefs is a class provided by Unity for persistent saving and reading of local data. The principle is very simple, it is to use the key-value method to save data locally, similar to a dictionary. Then save, read, and update operations through code. It is worth noting that this method can only save data of int type, float type, and string type . Of course, for bool type, 0 and 1 can be used instead of true and false to achieve the purpose of saving.

This uses the PlayerPrefs method to implement data storage and file reading. These two methods are written in GameManager.

//用Playerprefs方法对数据进行存储和读档
    private void SaveByPlayerPrefs()
    {
    
    
        PlayerPrefs.SetInt("bloodVolume", ScoreAndBlood._instance.BloodVolume);
        PlayerPrefs.SetInt("score", ScoreAndBlood._instance.Score);
        PlayerPrefs.Save();
    }
    private void LoadByPlayerPrefs()
    {
    
    
        if (PlayerPrefs.HasKey("bloodVolume") && PlayerPrefs.HasKey("score"))
        {
    
    
            ScoreAndBlood._instance.currentBloodVolume.text = PlayerPrefs.GetInt("bloodVolume").ToString();
            ScoreAndBlood._instance.currentScore.text = PlayerPrefs.GetInt("score").ToString();
        }
        else
        {
    
    
            Debug.Log("------未找到相应数据------");
        }
        
    }

Among them, the SaveByPlayerPrefs() method is written to save the blood volume and score in the form of key-value pairs through SetInt in PlayerPrefs. The LoadByPlayerPrefs() method is written to first determine whether these two keys are saved, and then set the saved values ​​through GetInt.

Here's what to do when clicking the Save Game and Load Game buttons

//点击保存和加载游戏的方法
    public void ClickSaveGame()
    {
    
    
        SaveByPlayerPrefs();//通过PlayerPrefs方式保存
    }
    public void ClickLoadGame()
    {
    
    
        LoadByPlayerPrefs();//通过PlayerPrefs方式读取
    }

(2) Serialization and deserialization
When saving, first create a binary formatter, then create a file stream, serialize the Date through the formatter and save it locally. When reading, a binary formatter is first created, a file stream is created, the Date is deserialized through the formatter, and then the game data is reset.

//用二进制方法对数据进行保存和读档
    private void SaveByBin()
    {
    
    
        try
        {
    
    
            Date date = GetGameDate();
            BinaryFormatter bf = new BinaryFormatter();//创建二进制格式化程序
            using (FileStream fs = File.Create(Application.dataPath + "/SaveFiles" + "/byBin.txt"))  //创建文件流
            {
    
    
                bf.Serialize(fs, date); //将date序列化
            }
        }
        catch (System.Exception e)
        {
    
    
            Debug.Log(e.Message);
        }
    }
    private void LoadByBin()
    {
    
    
        try
        {
    
    
            BinaryFormatter bf = new BinaryFormatter();
            using (FileStream fs = File.Open(Application.dataPath + "/SaveFiles" + "/byBin.txt", FileMode.Open))
            {
    
    
                Date date = (Date)bf.Deserialize(fs);//将date反序列化并赋值给date
                SetGameDate(date);
            }
        }
        catch (System.Exception e)
        {
    
    
            Debug.Log(e.Message);
        }
    }

The using directive is used here because the file stream needs to be closed after it is created. If the using directive is used, it will be closed automatically, eliminating one step of closing, that is, fs.Close();

This is how to click Save Game and Load Game

//点击保存和加载游戏的方法
    public void ClickSaveGame()
    {
    
    
        //SaveByPlayerPrefs();//通过PlayerPrefs方式保存
        SaveByBin();//通过二进制的方式保存
    }
    public void ClickLoadGame()
    {
    
    
        //LoadByPlayerPrefs();//通过PlayerPrefs方式读取
        LoadByBin();//通过二进制的方式读取
    }

After successfully saving, you can see a bin file in SaveFile. After opening it, you will see:
Insert image description here
From this, it can be seen that the readability of using the binary method is not good.

(3) Json
This is the plug-in required to use Json in unity:
https://download.csdn.net/download/qq_41294510/87996770
When using it, just drag it directly into Assets.
Json is a lightweight data exchange format. It is very convenient to use Json to store and read data in Unity.

//用Json方法对数据进行保存和读取
    private void SaveByJson()
    {
    
    
        Date date = GetGameDate();
        string datapath = Application.dataPath + "/SaveFiles" + "/byJson.json";
        string dateStr = JsonMapper.ToJson(date);  //利用JsonMapper将date转换成字符串
        StreamWriter sw = new StreamWriter(datapath); //创建一个写入流
        sw.Write(dateStr);//将dateStr写入
        sw.Close();//关闭流

    }
    private void LoadByJson()
    {
    
    
        string datePath = Application.dataPath + "/SaveFiles" + "/byJson.json";
        if (File.Exists(datePath ))  //判断这个路径里面是否为空
        {
    
    
            StreamReader sr = new StreamReader(datePath);//创建读取流;
            string jsonStr = sr.ReadToEnd();//使用方法ReadToEnd()遍历的到保存的内容
            sr.Close();
            Date date = JsonMapper.ToObject<Date>(jsonStr);//使用JsonMapper将遍历得到的jsonStr转换成Date对象
            SetGameDate(date);
        }
        else
        {
    
    
            Debug.Log("------未找到文件------");
        }
    }

Here's what to do when clicking the save and load buttons

//点击保存和加载游戏的方法
    public void ClickSaveGame()
    {
    
    
        //SaveByPlayerPrefs();//通过PlayerPrefs方式存储
        //SaveByBin();//通过二进制的方式存储
        SaveByJson();//通过Json方式存储
    }
    public void ClickLoadGame()
    {
    
    
        //LoadByPlayerPrefs();//通过PlayerPrefs方式读取
        //LoadByBin();//通过二进制的方式读取
        LoadByJson();//通过Json方式读取
    }

After saving successfully, you will see a json file in SaveFile. After opening it, you will see: It can be seen that
Insert image description here
intersection is much more readable than the previous method.

(4) Xml
XML is more readable than Json, but the file is large, the format is complex, and it is not as simple as Json.

  //使用XML方法对数据进行保存和读取
    private void SaveByXml()
    {
    
    
        Date date = GetGameDate();
        string datePath = Application.dataPath + "/SaveFiles" + "/byXml.txt";
        XmlDocument xmlDoc = new XmlDocument();//创建XML文档
        XmlElement root = xmlDoc.CreateElement("saveByXml");//创建根节点,并设置根节点的名字
        root.SetAttribute("name", "savefile");//设置根节点的值
        //创建其他节点,并设置其他节点的值
        XmlElement bloodVolume = xmlDoc.CreateElement("bloodVolume");
        bloodVolume.InnerText = date.BloodVolume.ToString();
        XmlElement score = xmlDoc.CreateElement("score");
        score.InnerText = date.Score.ToString();
        //将子节点加入根节点,将根节点加入XML文档中
        root.AppendChild(bloodVolume);
        root.AppendChild(score);
        xmlDoc.AppendChild(root);
        xmlDoc.Save(datePath);
        
    }
    private void LoadByXml()
    {
    
    
        string datePath = Application.dataPath + "/SaveFiles" + "/byXml.txt";
        if (File.Exists(datePath))
        {
    
    
            Date date = new Date();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(datePath);  //加载这个路径下的xml文档

            XmlNodeList bloodVolume = xmlDoc.GetElementsByTagName("bloodVolume");//通过名字得到XML文件下对应的值
            date.BloodVolume = int.Parse(bloodVolume[0].InnerText);

            XmlNodeList score = xmlDoc.GetElementsByTagName("score");
            date.Score = int.Parse(score[0].InnerText);
            SetGameDate(date);
            
        }
        
    }

Here is the code for clicking the save button and load button:

 //点击保存和加载游戏的方法
    public void ClickSaveGame()
    {
    
    
        //SaveByPlayerPrefs();//通过PlayerPrefs方式存储
        //SaveByBin();//通过二进制的方式存储
        //SaveByJson();//通过Json方式存储
        SaveByXml();//通过XML方式存储
    }
    public void ClickLoadGame()
    {
    
    
        //LoadByPlayerPrefs();//通过PlayerPrefs方式读取
        //LoadByBin();//通过二进制的方式读取
        //LoadByJson();//通过Json方式读取
        LoadByXml();//通过XML方式读取
    }

After successfully saving, you can see a txt file in SaveFile. After opening it, you will see:
Insert image description here
From this, you can see that the file is larger, but the readability is better.


Here is all the code for GameManager:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//引用命名空间
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using LitJson;
using System.Xml;

public class GameManager : MonoBehaviour
{
    
    

    //创建Data对象,并向其中添加游戏需要保存的数据
    private Date GetGameDate()
    {
    
    
        Date date = new Date();
        date.BloodVolume = ScoreAndBlood._instance.BloodVolume;
        date.Score = ScoreAndBlood._instance.Score;

        return date; 
    }
    //向游戏中加载Date中保存的数据的方法
    private void SetGameDate( Date date)
    {
    
    
        ScoreAndBlood._instance.currentBloodVolume.text = date.BloodVolume.ToString();
        ScoreAndBlood._instance.currentScore.text = date.Score.ToString();
    }

    
    //用Playerprefs方法对数据进行存储和读档
    private void SaveByPlayerPrefs()
    {
    
    
        PlayerPrefs.SetInt("bloodVolume", ScoreAndBlood._instance.BloodVolume);
        PlayerPrefs.SetInt("score", ScoreAndBlood._instance.Score);
        PlayerPrefs.Save();
    }
    private void LoadByPlayerPrefs()
    {
    
    
        if (PlayerPrefs.HasKey("bloodVolume") && PlayerPrefs.HasKey("score"))
        {
    
    
            ScoreAndBlood._instance.currentBloodVolume.text = PlayerPrefs.GetInt("bloodVolume").ToString();
            ScoreAndBlood._instance.currentScore.text = PlayerPrefs.GetInt("score").ToString();
        }
        else
        {
    
    
            Debug.Log("------未找到相应数据------");
        }
        
    }


    //用二进制方法对数据进行保存和读档
    private void SaveByBin()
    {
    
    
        try
        {
    
    
            Date date = GetGameDate();
            BinaryFormatter bf = new BinaryFormatter();//创建二进制格式化程序
            using (FileStream fs = File.Create(Application.dataPath + "/SaveFiles" + "/byBin.txt"))  //创建文件流
            {
    
    
                bf.Serialize(fs, date);
            }
        }
        catch (System.Exception e)
        {
    
    
            Debug.Log(e.Message);
        }
    }
    private void LoadByBin()
    {
    
    
        try
        {
    
    
            BinaryFormatter bf = new BinaryFormatter();
            using (FileStream fs = File.Open(Application.dataPath + "/SaveFiles" + "/byBin.txt", FileMode.Open))
            {
    
    
                Date date = (Date)bf.Deserialize(fs);
                SetGameDate(date);
            }
        }
        catch (System.Exception e)
        {
    
    
            Debug.Log(e.Message);
        }
    }


    //用Json方法对数据进行保存和读取
    private void SaveByJson()
    {
    
    
        Date date = GetGameDate();
        string datapath = Application.dataPath + "/SaveFiles" + "/byJson.json";
        string dateStr = JsonMapper.ToJson(date);  //利用JsonMapper将date转换成字符串
        StreamWriter sw = new StreamWriter(datapath); //创建一个写入流
        sw.Write(dateStr);//将dateStr写入
        sw.Close();//关闭流

    }
    private void LoadByJson()
    {
    
    
        string datePath = Application.dataPath + "/SaveFiles" + "/byJson.json";
        if (File.Exists(datePath ))  //判断这个路径里面是否为空
        {
    
    
            StreamReader sr = new StreamReader(datePath);//创建读取流;
            string jsonStr = sr.ReadToEnd();//使用方法ReadToEnd()遍历的到保存的内容
            sr.Close();
            Date date = JsonMapper.ToObject<Date>(jsonStr);//使用JsonMapper将遍历得到的jsonStr转换成Date对象
            SetGameDate(date);
        }
        else
        {
    
    
            Debug.Log("------未找到文件------");
        }
    }


    //使用XML方法对数据进行保存和读取
    private void SaveByXml()
    {
    
    
        Date date = GetGameDate();
        string datePath = Application.dataPath + "/SaveFiles" + "/byXml.txt";
        XmlDocument xmlDoc = new XmlDocument();//创建XML文档
        XmlElement root = xmlDoc.CreateElement("saveByXml");//创建根节点,并设置根节点的名字
        root.SetAttribute("name", "savefile");//设置根节点的值
        //创建其他节点,并设置其他节点的值
        XmlElement bloodVolume = xmlDoc.CreateElement("bloodVolume");
        bloodVolume.InnerText = date.BloodVolume.ToString();
        XmlElement score = xmlDoc.CreateElement("score");
        score.InnerText = date.Score.ToString();
        //将子节点加入根节点,将根节点加入XML文档中
        root.AppendChild(bloodVolume);
        root.AppendChild(score);
        xmlDoc.AppendChild(root);
        xmlDoc.Save(datePath);
        
    }
    private void LoadByXml()
    {
    
    
        string datePath = Application.dataPath + "/SaveFiles" + "/byXml.txt";
        if (File.Exists(datePath))
        {
    
    
            Date date = new Date();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(datePath);  //加载这个路径下的xml文档

            XmlNodeList bloodVolume = xmlDoc.GetElementsByTagName("bloodVolume");//通过名字得到XML文件下对应的值
            date.BloodVolume = int.Parse(bloodVolume[0].InnerText);

            XmlNodeList score = xmlDoc.GetElementsByTagName("score");
            date.Score = int.Parse(score[0].InnerText);
            SetGameDate(date);
            
        }
        
    }

    //点击保存和加载游戏的方法
    public void ClickSaveGame()
    {
    
    
        //SaveByPlayerPrefs();//通过PlayerPrefs方式存储
        //SaveByBin();//通过二进制的方式存储
        //SaveByJson();//通过Json方式存储
        SaveByXml();//通过XML方式存储
    }
    public void ClickLoadGame()
    {
    
    
        //LoadByPlayerPrefs();//通过PlayerPrefs方式读取
        //LoadByBin();//通过二进制的方式读取
        //LoadByJson();//通过Json方式读取
        LoadByXml();//通过XML方式读取
    }
}

Okay, the above is a simple case of using these four methods to save and read data. The specific method to use depends on the actual situation.

Guess you like

Origin blog.csdn.net/qq_41294510/article/details/131536416