Unity中使用的四种存档和读档方式

您所在的位置:网站首页 如何设置存档和隐藏 Unity中使用的四种存档和读档方式

Unity中使用的四种存档和读档方式

2023-11-10 12:18| 来源: 网络整理| 查看: 265

这里会列举四种存档方式,并且以简单的项目展示出效果。

这里我会写的简单易懂些,希望大家学到的是存档与读档的逻辑。

1.第一种方式: Unity自带的存档方式 干货:PlayerPrefs:数据持久化方案。 采用键值对的方式对数据进行存储。 eg:PlayerPrefs.SetInt("Index",1); 可以存储Int, Float, String类型的数据。 eg:PlayerPrefs.SetFloat("Height",183.5f); PlayerPrefs.SetString("Name","Tom"); 获取数据: eg:PlayerPrefs.GetInt("Index"); Serialization(序列化),可以用来将对象转化为字节流。 Deserialization(反序列化),可以用来将字节流转换为对象。

项目阐述:

首先,我们在一个空项目中新建一个Toggle,并给Canvas添加一个 Audio Source 组件和一个脚本,脚本 名根据个人需求,(我这里是MusicManager)效果图如下:

音乐素材资源,百度网盘链接:https://pan.baidu.com/s/1201WQaMSr1NUgZcvcrzG1A 提取码:rvqq

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 代码部分:

代码的功能就是:通过单选框是否被勾选上,从而来决定是否播放背景音乐。除此之外, 用Unity的 PlayerPrefs 存储方案来记录我们的选择,当我们再次运行时,会展示我们上一次运行的结果。小伙伴们快点试试吧! 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(); } }

最后,记得赋值: 在这里插入图片描述

2.第二种方式:二进制方法 干货:二进制方法(Binary Formatter) 序列化:新建或打开一个二进制文件,通过二进制格式器将对象写入该二进制文件。 反序列化:打开待反序列化的二进制文件,通过二进制格式器将文件解析成对象。

项目阐述:

项目百度网盘链接:链接:https://pan.baidu.com/s/1Xxn7yXTkFTEq65Vlz0tojg 提取码:9p4q 剩余的三种方式都以该项目阐述。 参考博客:http://blog.csdn.net/y1196645376/article/details/52541882

Ps:项目百度网盘链接里面有半成品和成品,半成品没有保存和加载功能,这里不建议小伙伴们拿着半成品跟着我的博客做, 希望小伙伴们学的是一种存储的思路。 参考博客是一位大佬写的, 小伙伴们可以用Unity打开成品里面的GameManager脚本,参照着那篇博客食用。也可以接着看完。

项目介绍:

1.UI层面解锁:这个游戏是一个第一人称射击游戏,当我们控制鼠标发射子弹击中箱子后,射击数会增加,得分 会增加。 1.1 当我们菜单栏显示时,即为游戏的暂停状态,游戏内的物品不可交互。不可射击,箱子不可生成。 1.2 当我们每发射一次子弹,则发射数自增1,击中箱子后得分自增1. 2.GameObject层面解锁: 2.1 箱子 这里箱子用协程写了随机生成、随机生命周期(未被击中时)、击中后0.3s失活。 2.2 箱子 这里箱子的种类有4种,红、橙、黄、绿,各个标志位之间的生成互不影响。种类编号0至3. 2.3 箱子 这里箱子一共有5个标志位,从左至右序号为 0至4。 2.4 枪 这里枪发射子弹的CD为1s一次,而箱子被击中后会在0.3s后消失,这就避免了每个箱子被击 中两次,从而避免了重复加分。

在这里插入图片描述

3.逻辑层面解锁: 3.1 先来给小伙们们理一下我们保存游戏的一个逻辑。 当我们点击保存游戏后,比如说我们的射击数是30,得分是20,场景中第一个标志位处有一个红箱 子,最后一个标志位处有一个橙箱子。其余标准位没有箱子。 那么我们加载游戏时,场景中应当也是 射击数是30,得分是20 第一个标志位处有一个红箱子, 最后一个标志位处有一个橙箱子,其余标志位没有箱子。 这就是我们为什么给箱子设置标志位和种类的原因了,我们点击保存游戏后,存储当前箱子的标志 位和种类的具体值,(比如我们将所有的标志位放进一个数组中,让一个GameObject类型的字符持续接收该数组中已 激活的箱子,我们在用户点击保存游戏时,记录下该GameObject类型的字符)而当加载游戏被点击时,我们返回给用 户当初保存时的数据和游戏对象。

代码展示:首先是二进制方法

我们先是Save方法,用于存储当前游戏状态信息. using System.Collections.Generic; [System.Serializable] public class Save { public List livingTargetPointions = new List(); public List livingMonsterTypes = new List(); public int shootNum = 0; public int score = 0; } 这个方法是用于记录箱子的状态信息,存储到Save方法中. // 按照给定的怪物类型激活怪物 // 停止所有协程 // 将当前激活状态的箱子(如果有的话)转为为激活状态 // 激活给定类型的怪物 public void ActivateMonsterByType(int type) { StopAllCoroutines(); // 当保存游戏后场景中仍然有箱子, 先将其隐藏,然后让activeMonster为null , // 等加载时 赋给 activeMonster 保存前的箱子类型 , 然后让其显示并开启 BoxCollider // 然后开启死亡协程 if (activeMonster != null) { activeMonster.GetComponent().enabled = false; activeMonster.SetActive(false); activeMonster = null; } activeMonster = monsters[type]; activeMonster.SetActive(true); activeMonster.GetComponent().enabled = true; StartCoroutine(DeathTimer()); } Save中的存储信息通过该方法反馈给每一个读档方式。这个方法是读档方法的辅助方法。每个读档方法方法都要调 用它。 // 通过读档信息重置我们的游戏状态 (分数、激活状态的怪物) private void SetGame(Save save) { // 先将所有的target里面的怪物清空,并重置所有的计时 foreach (GameObject targetGO in targetsGOs) { targetGO.GetComponent().UpdateMonsters(); } // 通过反序列化得到的Save 对象中存储的信息,激活指定的怪物 for (int i = 0; i // 序列化过程 (将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("存档文件不存在!"); } }

这里我的射击数是 14 得分是7 ,已经点击保存游戏,我的 Project 面板下的 StreamingFile文件夹就会自动创建一个 byBin.txt文件。看下图 在这里插入图片描述 在这里插入图片描述 如果是一堆这样的代码则说明保存成功, 否则则未保存成功! 在这里插入图片描述

当点击加载游戏按钮后,读档方法会解析自动创建的(你命名的文件)。 第三种方法 :Json 方法 干货:JSON:是一种语言无关的发送和接收数据的常用格式。可以使用它来跨平台的传输数据。 JSON序列化:对象 ——> JSON JSON反序列化:JSON ——> 对象

公共部分代码我就不再重复了,辅助工作还是和二进制的一样。

Json 读档和存档 Json 需要一个系统性的Json文件 (半成品和成品中都有,我就不发链接了)看图,先导入该文件再添加(using LitJson;)命名空间. 保存路径规则 还是一样的 . 读档路径必须和存档路径相同,绝大多数我们写这种功能代码时,都是先写存档再读档. 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(jsonStr); SetGame(save); UIManager._Instance.ShowMessage(" "); } else { UIManager._Instance.ShowMessage(" 存档文件不存在!"); } } 先导入该文件再添加(using LitJson;)命名空间. 这种方法可以看的懂读档。下图.

在这里插入图片描述 我保存后,注意场上的 1和3 标志位 有箱子,箱子序号种类 下图。 在这里插入图片描述 这里我的射击数是 14 得分是7 ,已经点击保存游戏,我的 Project 面板下的 StreamingFile文件夹就会自动创建一个 byJson.txt文件。看下图 在这里插入图片描述

可以用 文本打开 也可以用VS. 下面仔细看 射击数和得分是没有问题的。 在这里插入图片描述

标志位1 中的橙箱子激活和标志位3的黄箱子激活,所以标志位序号为 1,3。我们来看一下橙箱子和黄箱子的编号。 在这里插入图片描述 橙箱子编号 为 1 在这里插入图片描述 黄箱子编号 为 2 在这里插入图片描述

所有 byJson.txt中 先是标志位的序号(1,3),再是已激活箱子的编号(1,2),最后是射击数和得分。

在这里插入图片描述

第四种方法: Xml方法 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 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("存档文件不存在"); } } 我先带大家理出答案,我们再看自动创建的byXML.txt文件。

当我保存游戏后 ,场景中是有4个箱子的。标志位序号为 0,1,2,3 。(红橙黄绿)箱子编号为: Scene 面板从右至左,Game窗口从左至右,以Game窗口为准, 橙箱子 1 黄箱子 2 红箱子 0 橙箱子1.

在这里插入图片描述

自动创建的byXML文件. 在这里插入图片描述

标志位序号为 0 , 1, 2, 3 橙箱子 1 黄箱子 2 红箱子 0 橙箱子1 竖着看, 标志位0 的是橙色箱子 1 . 以此类推....

在这里插入图片描述 三种方式的对比:

二进制方法:简单,但可读性差。 XML:可读性强,但是文件庞大,冗余信息多。 JSON:数据格式比较简单,易于读写,但是不直观,可读性比XML差。

感谢小伙伴们的观看,没看懂的话去看我上面的那条链接大佬的博客。拜拜!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3