简单的介绍几种在unity中对数据的存储和读档的方法!

简单的介绍几种在unity中对数据的存储和读档的方法!

在unity中实现对游戏数据的存储和读档的方法主要有这么几种:

  • 使用本地持久化类PlayerPrefs
  • 使用二进制的方法序列化和反序列化(Serialize、Deserialize)
  • 使用Json方法
  • 使用XMl方法。

下面就通过一个简单的例子分别用这四种方法实现数据的存储和读档。


实现目标:
   做一个简单的得分制,按S键得分加一,按B键血量减一。UI设计上做一个保存按钮,用于保存数据,再做一个加载按钮,用于加载上一局保存的数据到场景中。

搭建场景: 由于比较简单,就不一一赘述了,直接上图:
在这里插入图片描述
主要的是说一下unity中Hierarchy面板中的结构,因为担心有些朋友搞混了。
在这里插入图片描述
首先呢,创建一个Canvas,他下面的两个image分别是血量和得分的背景(无关紧要),CurrentBloodVolume是个Text,用来显示当前的血量,CurrentScore也是个Text,用来显示当前的得分,save是个按钮,用来保存,load也是个按钮,用来加载,GameManager是个空物体,用来挂载GameManager脚本,这个脚本里面主要写了各种方法,游戏逻辑,ScoreAndBlood也是个空物体,用来挂载ScoreAndBlood脚本,这个脚本里面写了加分和减血的代码。

脚本创建: 创建一个Date脚本,这个脚本不需要继承MonoBehaviour,因为这个脚本是用来序列化和反序列化的,需要向这个类中添加游戏需要保存的数据,最后要读档的时候也是需要从这个类中读取保存的数据。还需要一个加分和减血的类ScoreAndBlood,最后还有一个游戏主逻辑类GameManager。

我们在最开始先把几段必要的代码给出来:
加分和减血的代码:

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();
        }
    }
}

需要存储和读取游戏数据的脚本Date:

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

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

GameManager脚本中向Date中存放数据和从Date中读取数据的方法

  //创建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
PlayerPrefs是unity提供的一个用于本地数据持久化保存、读取的类。原理很简单,就是利用key—value的方式将数据保存到本地,跟字典类似。然后通过代码进行保存、读取、更新操作。值得注意的是此方法只能保存int型、float型,string型的数据,当然,对于bool类型的可以用0和1来代替真和假,以实现保存目的。

这是用PlayerPrefs方法实现数据存储与读档的,这俩方法写在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("------未找到相应数据------");
        }
        
    }

其中SaveByPlayerPrefs()方法中写了通过PlayerPrefs中的SetInt将血量和得分通过键值对的形式保存下来。LoadByPlayerPrefs()方法中写了先判断一下是否有保存了这两个键,然后再通过GetInt去设置保存下来的值。

这是点击保存游戏和加载游戏按钮要执行的方法

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

(二)序列化和反序列化
保存的时候首先创建二进制格式化程序,然后创建文件流,通过格式化程序将Date进行序列化并保存到本地。读取的时候也是先创建二进制格式化程序,创建文件流,通过格式话程序将Date反序列化出来,然后重新设置游戏数据。

//用二进制方法对数据进行保存和读档
    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);
        }
    }

这里使用using指令是因为文件流创建后需要关闭,如果使用using指令的话就自动关闭掉了,省去了一步关闭的步骤,即fs.Close();

这是点击保存游戏和加载游戏要执行的方法

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

保存成功后可以在SaveFile中看到一个bin文件打开后会看到:
在这里插入图片描述
由此看见,使用二进制的方法可读性不好

(三)Json
这是在unity中使用Json所需要的插件:
https://download.csdn.net/download/qq_41294510/87996770
使用时直接将其拖动到Assets中就可以。
Json是一种轻量级的数据交换格式,使用Json在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("------未找到文件------");
        }
    }

以下是点击保存和加载按钮要执行的方法

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

保存成功后会看到保存成功后可以在SaveFile中看到一个json文件打开后会看到:
在这里插入图片描述
由此可见,相交与上一种方法可读性要好很多

(四)Xml
XML相较于Json来说可读性要比较好,但文件庞大,格式复杂,没有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);
            
        }
        
    }

以下是点击保存按钮和加载按钮的代码:

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

保存成功后可以在SaveFile中看到一个txt文件打开后会看到:
在这里插入图片描述
由此看见文件比较大,但是可读性要好。


以下是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方式读取
    }
}

好了,以上就是使用这四种方法保存与读取数据的一个简单案例。具体使用那种方法还是要按照实际情况来。

猜你喜欢

转载自blog.csdn.net/qq_41294510/article/details/131536416