小言_互联网的博客

Unity实现数据存储和读取持久化(PlayerPrefs、序列化、JSON、XML)

296人阅读  评论(0)

说来惭愧,之前甚至连这个都没学
用文件的形式存储,其实有很多种不同办法都能实现。
但是这学期时间有限,所以打算学习其中的四种,目前只是做demo,所以使用的方法都是小白级别的。

一、Unity自带-PlayerPrefs

简单介绍

存储读取数据只有对应的三种方法,非常方便。缺点是只能存储三种数据形式——int float string
使用就只有一种套路:

//在Player preference里面存入对应三种不同数据形式的键值对
PlayerPrefs.SetInt/SetFloat/SetString(String name,不同数据类型对应的值);
//在Player preference中查找对应键的值并返回
PlayerPrefs.GetInt/GetFloat/GetString(String name);

实现

在场景里面新建一个文本框,里面是我们要保存的数据,然后建立一个保存按钮和一个加载按钮。当按下空格的时候,里面的数字+1。

实现加分

书写ScoreAdd脚本,脚本随便挂载到一个物体上,并且把Text拖拽到脚本numText对象赋值;
使得按下空格的时候分数+1,

public class scoreAdd: MonoBehaviour
{
   
    private int num;
    public Text numText;
    private void Awake() {
   
        num = 0;
    }
    void Update()
    {
   
        if (Input.GetKeyDown(KeyCode.Space)) {
   
            num++;
            Debug.Log("Score added");
            numText.text = num.ToString();
        }   
    }
}

实现保存和读取

为了让其他脚本能读取到num的数据,我们对scoreAdd脚本修改一下,把num改为public类型并且开启单例让其他脚本能访问到它。

public class scoreAdd : MonoBehaviour
{
   
    public static scoreAdd instance;
    
    public int num;
    public Text numText;
    private void Awake() {
   
        if (instance == null) {
   
            instance = this;
        }
    }
    void Update()
    {
   
        numText.text = num.ToString();
        if (Input.GetKeyDown(KeyCode.Space)) {
   
            num++;
            Debug.Log("Score added");
        }   
    }
}

然后我们建立新的脚本usePlayerPrefs,书写如下代码。

public class usePlayerPrefs : MonoBehaviour
{
   
    public void playerPrefsSave() {
   
        PlayerPrefs.SetInt("MyScore", scoreAdd.instance.num);
        Debug.Log("Score has saved");
    }
    public void playerPrefsLoad() {
   
        scoreAdd.instance.num = PlayerPrefs.GetInt("MyScore");
        Debug.Log("Score had loaded");
    }
}

然后也是随便拖到一个物体上
在inspector给Save按钮OnClick添加playerPrefsSave事件;
Load按钮添加playerPrefsLoad事件

然后运行游戏,先把数字加到任意一个数,(我选择8)

按下Save。

重新开始场景

按下Load按钮,发现数字变为8,(~ ̄▽ ̄)~

二、序列化和反序列化-二进制格式化

相比于PlayerPres,只需要创建一个类来存储数据,存储的时候将其序列化成二进制文件(序列化),读取的时候将其反序列为类。
并且由于是二进制格式存储,玩家比较难篡改(大概)。

简单介绍

1.序列化
Serialization
对象的状态信息转换为Unity可以存储文件的形式的自动化处理过程,或者简单来说是把对象转化为可传输的字节序列的过程。

2.文件
File
C#中的静态类,对文件进行操作:复制、创建、删除、移动(需要引入空间System.IO)

3.文件流
FileStream
对文件进行:读、写、关闭(需要引入空间System.IO)
反正就是需要什么操作就用什么类的函数

然后我们进行存储和读取的时候,借助一个类。
存储的时候新建一个类的对象,在这个类里面存放需要存放的数据,并把其序列化为一个二进制文件(也可以是其他类型),然后放进一个路径(一般都是Applicaiton.persistentDataPath);
读取的时候调用反序列化函数把这个文件变为之前的类就好了,(需要强制转化为之前类的类型

要注意的是,需要引入命名空间 System,才能把这个类声明为可序列化。

实现

建立脚本Save

	using System;
/// <summary>
/// 用于序列化成二进制文件的类
/// </summary>
[Serializable]
public class Save 
{
   
   public int Score;
}

建立脚本useSerialization

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;

public class useSerialization : MonoBehaviour
{
   
    /// <summary>
    /// 创建一个保存了数据的类
    /// </summary>
    /// <returns></returns>
    Save createSave() {
   
        Save save = new Save();
        save.Score = scoreAdd.instance.num;
        return save;
    }
    public void serializationSave() {
   
        Save save = createSave();
        //Inheritance Object -> BinaryFormatter
        BinaryFormatter bf = new BinaryFormatter();
        //创建存档文件
        FileStream fs = File.Create(Application.persistentDataPath + "/Data.text");
        //将save变为fs
        bf.Serialize(fs, save);
        fs.Close();
    }
    public void serializationLoad() {
   
        if(File.Exists(Application.persistentDataPath + "/Data.text")) {
   
            BinaryFormatter bf = new BinaryFormatter();
            //打开对应路径的存档文件
            FileStream fs = File.Open(Application.persistentDataPath + "/Data.text",FileMode.Open);
            Save save = bf.Deserialize(fs) as Save;
            fs.Close();
            scoreAdd.instance.num = save.Score;
        } else {
   
            Debug.LogWarning("Not Found Save File");
        }
    }
}

和PlayerPrefs一样,同样让两个按钮的OnClick添加对应的save和load委托。

进行测试

同样加到8,按下save

重新开始

按下Load按钮,发现数字变为8,(~ ̄▽ ̄)~

还有另外一个会继续更新,先更到这


接下来是Json和XML

三、JSON

不要被看起来高大上的名字吓跑,在Unity上利用Json进行数据读写并不困难。
JSON全称 JavaScript Object Notation 也就是一种符号表示法。相比于序列化为二进制文件,JSON把对象存储为JSON文件,本质是字符串

具体规则自行查找。

简单介绍

JSON同样以键值对的形式表示数据,string类型的键, int、bool、float 数组、对象的值
利用JSON和利用序列化存档的本质类似:
存储的时候新建一个类的对象,在这个类里面存放需要存放的数据,并利用JsonUtility 把其转化为一个JSON规则的字符串,再利用 StreamWriter生成文件,最后放进一个路径(一般都是Applicaiton.persistentDataPath);
读取的时候借助JsonUtility把这个文件变为之前的类就好了(泛型方法)。

实现

建立脚本Save

using System;
/// <summary>
/// 用于序列化成二进制文件的类
/// </summary>
[Serializable]
public class Save 
{
   
    public int Score;
}

建立脚本useJson

using System.IO;
using UnityEngine;

public class useJson : MonoBehaviour
{
   
   /// <summary>
    /// 创建一个保存了数据的类
    /// </summary>
    /// <returns></returns>
    Save createSave() {
   
        Save save = new Save();
        save.Score = scoreAdd.instance.num;
        return save;
    }
    public void jsonSave() {
   
        Save save = createSave();

        //Inheritance Object -> Json
        string jsonString = JsonUtility.ToJson(save);

        //创建StreamWrite,作用类似于类似于FileStream,生成存档文件
        StreamWriter sw = new StreamWriter(Application.persistentDataPath + "/JsonData.txt");
        sw.Write(jsonString);
        sw.Close();

        Debug.Log("Use Json to save project successed");
     }

    public void jsonLoad() {
   
        if(File.Exists(Application.persistentDataPath + "/JsonData.txt")) {
   
            StreamReader sr = new StreamReader (Application.persistentDataPath + "/JsonData.txt");
            string JsonString = sr.ReadToEnd();
            sr.Close();

            Save save = JsonUtility.FromJson<Save>(JsonString);
            //接下来要做什么操作自己决定
            scoreAdd.instance.num = save.Score;
            Debug.Log("Json Load successed");
        } else {
   
            Debug.Log("Not found Json Save File");
        }
    }
}

和PlayerPrefs一样,同样让两个按钮的OnClick添加对应的save和load委托。

进行测试

加到8,按下save

重新开始

按下Load按钮,变成8了ヾ(✿゚▽゚)ノ

四、XML

简单介绍

XML:Extensible Markup Language: 可扩展标记语言
不同系统之间的数据传输和交换非常消耗时间,并且可能产生一些丢失数据的情况。而XML以纯文本格式进行存储,使得在不同系统之间交换数据方便。本质就是字符串
由于Unity没有自带解析XML的系统,所以我们需要借助Csharp的System.Xml来操作
存储的时候新建一个类的对象,在这个类里面存放需要存放的数据,然后构造一个XmlDocument类型的对象,设立一个根结点,对于需要存放的数据构造XmlElement类型的键值对,并且作为根结点的子结点,最后再将根结点作为对象的子结点,最后保存文件放进一个路径(一般都是Applicaiton.persistentDataPath);
读取的时候需要根据之前存放的键值对的值取到对应的数据。

实现

建立脚本Save

略,和前面一样

建立脚本useXML

using UnityEngine;
using System.IO;
using System.Xml;

public class useXML : MonoBehaviour
{
   
    /// <summary>
    /// 创建一个保存了数据的类
    /// </summary>
    /// <returns></returns>
    Save createSave() {
   
        Save save = new Save();
        save.Score = scoreAdd.instance.num;
        return save;
    }
    public void saveByXML() {
   
        Save save = createSave();
        XmlDocument xmlDocument = new XmlDocument();

        #region CreateXML elements

        XmlElement root = xmlDocument.CreateElement("Save");
        //也不知道有什么用
        root.SetAttribute("FileName", "File_01");

        XmlElement scoreElement = xmlDocument.CreateElement("Score");
        //设置元素值
        scoreElement.InnerText = save.Score.ToString();
        root.AppendChild(scoreElement);
        #endregion
        
        //将根结点和其子结点加入前面新建的XML文件
        xmlDocument.AppendChild(root);
        xmlDocument.Save(Application.dataPath + "/XMLData.text");
        if (File.Exists(Application.dataPath + "/XMLData.text")) {
   
            Debug.Log("XML file save successed");
        }
    }
    public void loadByXML() {
   
        if (File.Exists(Application.dataPath + "/XMLData.text")) {
   
            Save save = new Save();

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(Application.dataPath + "/XMLData.text");

            //从XML中获得游戏数据
            XmlNodeList score = xmlDocument.GetElementsByTagName("Score");
            //score只有一个,所以是0号元素
            int number = int.Parse(score[0].InnerText);
            //获得数据赋予Save类
            save.Score = number;

            scoreAdd.instance.num = number;
        } else {
   
            Debug.Log("Load Failed");
        }
    }
}

进行测试

同样加到8,并且保存

重新启动

按下Load按钮,变成8了ヽ(゚∀゚)メ(゚∀゚)ノ

其实没有必要四个都会,精通一个就好了,现在觉得应该是json最适合目前的我。


转载:https://blog.csdn.net/qq_42883222/article/details/115981479
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场