11.20闲话-存档

存档

参考

使用没有存档的软件,就像吃饭不给容器一般。

故存档必然是极为重要的。

下面介绍Unity的几种存档方式。

代码出处

Part.1——PlayerPrefs

应该是最简单的存档方式。

但局限性也是显然的,只能存储int, float, string 三种类型,就像在文件中存储了三个map <string, int / float / string>

PlayerPrefs.SetInt("田所浩二", 114514); // 存
PlayerPrefs.SetString("涛哥", "原神");

string players_id = PlayerPrefs.GetString("涛哥"); // 读

Part.2——存储数据序列化

分为三种:二进制方法、XML方法、JSON方法,各有千秋。

大体就是

序列化 对象 -> 字节流

反序列化 字节流 -> 对象

先创建一个Save类,用于记录需要保存的东西

public class Save
{
    public List <string> HZOI_name = new List <string>();

    public int id;
}

1. 二进制方式

使用二进制文件进行序列化与反序列化

private void Save_By_Bin()
{
    Save save = Create_Save();

    BinaryFormatter bf = new BinaryFormatter(); // 创建二进制格式化进程

    FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile" + "/byBin.txt"); // 创建文件流

    bf.Serialize(fileStream, save);

    fileStream.Close(); // 关闭

    if (File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
    {
        Debug.Log("保存成功");
    }
}

private void Load_By_Bin()
{
    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)bf.Deserialize(fileStream);

        fileStream.Close();

        Set_Game(save);

        Debug.Log("成功");
    }
    else
    {
        Debug.Log("What are you doing?");
    }
}

2. JSON方法

使用JSON进行序列化与反序列化

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

    sw.Close();

    if (File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
    {
        Debug.Log("保存成功");
    }
}

private void LoadByJson()
{ 
    string filePath = Application.dataPath + "/StreamingFile" + "/byJson.json";
    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);//将保存的信息类初始游戏
    
        Debug.Log("成功");
    }
    else
    {
        Debug.Log("What are you doing?");
    }
}

XML方法

//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.livingTargetPositions.Count; i++)
    {
        target = xmlDoc.CreateElement("target");
        targetPosition = xmlDoc.CreateElement("targetPosition");
        //设置InnerText值
        targetPosition.InnerText = save.livingTargetPositions[i].ToString();
        monsterType = xmlDoc.CreateElement("monsterType");
        monsterType.InnerText = save.livingMonsterTypes[i].ToString();

        //设置节点间的层级关系 root -- target -- (targetPosition, monsterType)
        target.AppendChild(targetPosition);
        target.AppendChild(monsterType);
        root.AppendChild(target);
    }

    //设置射击数和分数节点并设置层级关系  xmlDoc -- root --(target-- (targetPosition, monsterType), id, score)
    XmlElement id = xmlDoc.CreateElement("id");
    id.InnerText = save.id.ToString();
    root.AppendChild(id);

    xmlDoc.AppendChild(root);
    xmlDoc.Save(filePath);
    
    if (File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
    {
        Debug.Log("保存成功");
    }
}


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.livingTargetPositions.Add(targetPositionIndex);

                XmlNode monsterType = target.ChildNodes[1];
                int monsterTypeIndex = int.Parse(monsterType.InnerText);
                save.livingMonsterTypes.Add(monsterTypeIndex);
            }
        }
        
        XmlNodeList id = xmlDoc.GetElementsByTagName("id");
        int shootNumCount = int.Parse(id[0].InnerText);
        save.id = shootNumCount;

        SetGame(save);//将保存的信息类初始游戏
        //TODO: 提示存档不存在或为空,读取成功

        Debug.Log("成功");
    }
    else
    {
        Debug.Log("What are you doing?");
    }
}

Part.3 总结

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

JSON方法:可读性好,感觉比较符合人类直觉

XML:冗长,可读性好(?没感觉可读性太好,可能是我太蒻了呜呜呜)

偶然发现

posted @ 2024-11-20 19:49  QEDQEDQED  阅读(28)  评论(4编辑  收藏  举报