Unity 常用的几种存档读档方式

Posted qq_20255239

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 常用的几种存档读档方式相关的知识,希望对你有一定的参考价值。

一、PlayerPrefs:数据持久化方案

常见的方法如下:

// PlayerPrefs读取
PlayerPrefs.GetInt("123asd");       // 如果我们之前没有过这个键,那么返回默认值就是0
PlayerPrefs.GetFloat("asd");        // 如果我们之前没有过这个键,那么返回默认值就是0
PlayerPrefs.GetString("123");       // 如果我们之前没有过这个键,那么返回默认值就是Null
​
// 我们是可以修改方法返回的默认值的,另外两个API同理
// 我们通常可以使用在玩家基础数据初始化
PlayerPrefs.GetInt("zzz", 100);     // 如果我们之前没有过这个键,那么返回默认值就是100
​
// PlayerPrefs判断数据是否存在
PlayerPrefs.HasKey("XXX");
​
// PlayerPrefs删除数据
PlayerPrefs.DeleteKey("XXX");       // 删除指定键值对的数据
PlayerPrefs.DeleteAll();            // 删除所有键值对的数据

 参考功能及代码:

通过单选框是否被勾选上,从而来决定是否播放背景音乐,代码如下:

using UnityEngine.UI;
public class MusicManager : MonoBehaviour

    // 音乐开关单选框  和 播放背景音乐的 musicAudio 组件
    public Toggle musicToggle;
    public Audiosource musicAudio;
    private void Awake()
    
      if (PlayerPrefs.HasKey("MusicOn"))
      
         if (PlayerPrefs.GetInt("MusicOn") == 1)
            
              //  当 单选框 勾选时, 激活 musicAudio 组件
                musicToggle.isOn = true;
                musicAudio.enabled = true;
            
            else
            
            //  当 单选框 未勾选时, 让 musicAudio 组件失活
                musicToggle.isOn = false;
                musicAudio.enabled = false;
            
      else
          
            musicToggle.isOn = true;
          
    
    private void Update()
    
        MusicSwitch();
    
    private void MusicSwitch() 
         // 通过单选框是否被勾选上,从而来决定是否播放背景音乐
        if (musicToggle.isOn == false)
        
            musicAudio.enabled = false;
            //   保存音乐开关的状态,   0代表暂停 1 代表播放
            PlayerPrefs.SetInt("MusicOn",0);  
        
        else 
            musicAudio.enabled = true;
            PlayerPrefs.SetInt("MusicOn", 1);
        
        PlayerPrefs.Save();
    

二、二进制存储(字节流存储)

序列化:新建或打开一个二进制文件,通过二进制格式器将对象写入该二进制文件。

反序列化:打开待反序列化的二进制文件,通过二进制格式器将文件解析成对象。

参考代码如下:

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
// 这两个命名空间需添加

// 二进制方法:存档和读档
    private void SaveByBin() 
        // 序列化过程 (将Save 对象转换为字节流)
        // 创建Save 对象 并 保存当前游戏状态 
        Save save = CreateSaveGO();
        // 创建一个二进制格式化程序
        BinaryFormatter bf = new BinaryFormatter();
        // 创建一个文件流
        FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile" + "/byBin.txt");
        // 用二进制格式化程序的序列化方法 来 序列化Save对象
        //      参数:创建的文件流和需要序列化的对象
        bf.Serialize(fileStream,save);
        // 关闭流
        fileStream.Close();

         // 如果文件存在,则显示保存成功
        if (File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt")) 
            UIManager._Instance.ShowMessage("保存成功!");
        
    
    private void LoadByBin() 

        if (File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
        
            // 反序列化过程
            // 创建一个二进制格式化程序
            BinaryFormatter bf = new BinaryFormatter();
            // 打开一个文件流
            FileStream fileStream = File.Open(Application.dataPath + "/StreamingFile" 
 + "/byBin.txt", FileMode.Open);
            // 调用格式化程序的反序列化方法,将文件流转换为Save 对象
            Save save = (Save)bf.Deserialize(fileStream);
            // 关闭文件流
            fileStream.Close();
            SetGame(save);
            UIManager._Instance.ShowMessage(" ");
        
        else  
            UIManager._Instance.ShowMessage("存档文件不存在!");
        

    

三、json存储

JSON序列化:对象 ——> JSON

JSON反序列化:JSON ——> 对象

参考代码如下:

using LitJson;
// 此命名空间需添加


// Json:  存档和读档
    private void SaveByJson()
    
        Save save = CreateSaveGO();
        string filePath = Application.dataPath + "/StreamingFile" + "/byJson.txt";
        // 利用 JsonMapper 将save 对象转换Wie Json 格式的字符串
        string saceJsonStr = JsonMapper.ToJson(save);
        // 将这个字符串写入到文件中
        // 创建一个StreamWriter,并将字符串写入文件中
        StreamWriter sw = new StreamWriter(filePath);
        sw.Write(saceJsonStr);
        // 关闭 StreamWrite
        sw.Close();

        UIManager._Instance.ShowMessage("保存成功!");
    
   
    private void LoadByJson() 
        string filePath = Application.dataPath + "/StreamingFile" + "/byJson.txt";
        if (File.Exists(filePath))
        
            // 创建一个 StreamReader, 用来读取流
            StreamReader sr = new StreamReader(filePath);
            // 将读取到的流赋值给 jsonStr
            string jsonStr = sr.ReadToEnd();
            // 关闭
            sr.Close();

            // 将字符串jsonStr 转换为Save 对象
            Save save = JsonMapper.ToObject<Save>(jsonStr);
            SetGame(save);
            UIManager._Instance.ShowMessage(" ");
        
        else 
            UIManager._Instance.ShowMessage(" 存档文件不存在!");
        
    

注:需先导入该文件再添加(using LitJson;)命名空间,LitJson文件存于百度网盘链接:https://pan.baidu.com/s/1Wor_lltGnGbbBmD2T0Dtqg 
提取码:wdrf

四、XML存储

扩展标记语言,用于标记电子文件使其具有结构性的标记语言。 可以用来标记数据、定义数据类型。 序列化与反序列化的方式与二进制方法十分类似。

参考代码如下:

using System.Xml;
//需要添加该命名空间
// Xml:  存档和读档
    private void SaveByXml() 
        Save save = CreateSaveGO();
        // 创建Xml 文件的存储路径
        string filePath = Application.dataPath + "/StreamingFile" + "/byXML.txt";
        // 创建XML 文档
        XmlDocument xmlDoc = new XmlDocument();
        // 创建根节点, 即最上层节点
        XmlElement root = xmlDoc.CreateElement("save");
        // 设置根节点中的值
        root.SetAttribute("name","saveFile1");

        // 创建XmlElement
        XmlElement target;
        XmlElement targetPosition;
        XmlElement monsterType;

        // 遍历 save中存储的数据,将数据转换成XML格式
        for (int i =0; i < save.livingTargetPointions.Count;i++) 
            target = xmlDoc.CreateElement("target");
            targetPosition = xmlDoc.CreateElement("targetPosition");
            // 设置 InnerText 值
            targetPosition.InnerText = save.livingTargetPointions[i].ToString();
            monsterType = xmlDoc.CreateElement("monsterType");
            monsterType.InnerText = save.livingMonsterTypes[i].ToString();

            // 把节点一层层的添加至 XMLDoc 中,请仔细看他们之间的先后顺序,这将是生成XML 文件的顺序
             // 设置节点间的层级关系 root ---- target ---- (targetPosition,monsterType)
            target.AppendChild(targetPosition);
            target.AppendChild(monsterType);
            root.AppendChild(target);
        
        // 设置射击数和分数节点  并设置层级关系  xmlDoc---- root----(
        //  target---- (targetPosition,monsterType), shootNum , score);
        XmlElement shootNum = xmlDoc.CreateElement("shootNum");
        shootNum.InnerText = save.shootNum.ToString();
        root.AppendChild(shootNum);
        
        XmlElement score = xmlDoc.CreateElement("score");
        score.InnerText = save.score.ToString();
        root.AppendChild(score);

        xmlDoc.AppendChild(root);
        xmlDoc.Save(filePath);

        if (File.Exists(Application.dataPath + "/StreamingFile" + "/byXML.txt"))  
            UIManager._Instance.ShowMessage("保存成功!");
        
    
    private void LoadByXml() 
        string filePath = Application.dataPath + "/StreamingFile" + "/byXML.txt";
        if (File.Exists(filePath))
        
            Save save = new Save();
            // 加载XML 文档
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            // 通过节点名称来获取元素,结果为XmlNodeList类型
            XmlNodeList targets = xmlDoc.GetElementsByTagName("target");
            // 遍历所有的 target 节点,并获取子节点和子节点的InnerText
            if (targets.Count != 0) 
                foreach (XmlNode target  in targets) 
                    XmlNode targetPosition = target.ChildNodes[0];
                    int targetPositionIndex = int.Parse(targetPosition.InnerText);
                    // 把得到的值存储到 save 中
                    save.livingTargetPointions.Add(targetPositionIndex);
                    XmlNode monsterType = target.ChildNodes[1];
                    int monsterTypeIndex = int.Parse(monsterType.InnerText);
                    save.livingMonsterTypes.Add(monsterTypeIndex);

                
            
            // 得到存储的射击数
            XmlNodeList shootNum = xmlDoc.GetElementsByTagName("shootNum");
            int shootNumCount = int.Parse(shootNum[0].InnerText);
            save.shootNum = shootNumCount;

            XmlNodeList score = xmlDoc.GetElementsByTagName("score");
            int scoreCount = int.Parse(score[0].InnerText);
            save.score = scoreCount;
            SetGame(save);
            UIManager._Instance.ShowMessage(" ");
        
        else 
            UIManager._Instance.ShowMessage("存档文件不存在");
        
    

后三种方法优缺点对比:

二进制方法:简单,但可读性差。

XML:可读性强,但是文件庞大,冗余信息多。

JSON:数据格式比较简单,易于读写,但是不直观,可读性比XML差。

参考链接:Unity中使用的四种存档和读档方式_Wisdom_off的博客-CSDN博客_unity 存档

以上是关于Unity 常用的几种存档读档方式的主要内容,如果未能解决你的问题,请参考以下文章

unity游戏中存档和读档的方法

SIKI_Unity_2_入门_通过实例学习游戏的存档和读档

Unity开发之存档和读档的三种实现方式

Unity - 存读档机制简析

Unity 之 查找游戏物体的几种方式解析

#yyds干货盘点# 100个 Unity小知识点 | Unity中常用的几种单例写法