存档与读档功能

举例:

  • 传统RPG游戏(仙剑、空之轨迹):

    1.角色信息(生命值,等级)

    2.道具信息(装备,药品)

    3.场景信息(场景名称、角色坐标)

    4.事件信息(任务相关)

  • 关卡类游戏:关卡的通关情况

  • 一些特殊的存档机制(漫漫长夜、亿万僵尸)

Unity中使用的存档方式

一、PlayerPrefs:数据持久化方案

官方手册

  1. 原理:采用键值对的方式对数据进行存储---保存在本地文件(不同操作系统存储路径不同)中,然后程序可以根据这个名称取出上次保存的数值)

  2. 储存类型:可以存储Int, Float, String类型的数据。

  3. 使用例子

//存储数据:
PlayerPrefs.SetInt("Index",1);
PlayerPrefs.SetFloat("Height",183.5f);
PlayerPrefs.SetString("Name","Tom");
//获取数据:
PlayerPrefs.GetInt("Index");

二、存储数据序列化

  • Serialization(序列化),可以用来将对象转化为字节流。
  • Deserialization(反序列化),可以用来将字节流转换为对象。
  • 常见的数据序列化方法:二进制方法,XML方法,JSON方法
  • 存储在:内存、文件、数据库--可存于本地或云

++下面以实例说明++:

Save类--用于保存信息

using System.Collections;
using System.Collections.Generic;
using UnityEngine; [System.Serializable]
public class Save{
//怪物位置
public List<int> livingTargetPositions = new List<int>();
//怪物类型
public List<int> livingMonsterTypes = new List<int>();
//得分情况
public int shootNum = 0;
public int score = 0;
}
  1. 二进制存储(Binary Formatter)
  • 序列化:新建或打开一个二进制文件,通过二进制格式器将对象写入该二进制文件。
  • 反序列化:打开待反序列化的二进制文件,通过二进制格式器将文件解析成对象。
//二进制方法:存档和读档
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"))
{
//TODO: 提示保存成功
}
} 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); //将保存的信息类初始游戏
//TODO: 提示存档不存在或为空,读取成功 }
else
{
//TODO: 提示存档不存在或为空,读取失败
} }
  1. Json存储
  • JSON:是一种语言无关的发送和接收数据的常用格式。可以使用它来跨平台的传输数据。
  • JSON序列化:
graph LR
对象-->JSON
  • JSON反序列化:
graph LR
JSON-->对象
//JSON:存档和读档
private void SaveByJson()
{
Save save = CreateSaveGO();
string filePath = Application.dataPath + "/StreamingFile" + "/byJson.json";
//利用JsonMapper将save对象转换为Json格式的字符串
string saveJsonStr = JsonMapper.ToJson(save);
//将这个字符串写入到文件中
//创建一个StreamWriter,并将字符串写入文件中
StreamWriter sw = new StreamWriter(filePath);
sw.Write(saveJsonStr);
//关闭StreamWriter
sw.Close(); //TODO: 提示保存成功
} 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);//将保存的信息类初始游戏
//TODO: 提示存档不存在或为空,读取成功
}
else
{
//TODO: 提示存档不存在或为空,读取失败
}
}

存储效果:

{
"livingTargetPositions":[0,1,2,4,5,8],
"livingMonsterTypes":[2,1,2,0,3,0],
"shootNum":18,
"score":9
}
  1. XML存储

XML:扩展标记语言,用于标记电子文件使其具有结构性的标记语言。

  • 可以用来标记数据、定义数据类型。
  • 序列化与反序列化的方式与二进制方法十分类似。

XML与Json的区别

//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), 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"))
{
//TODO: 提示保存成功
}
} 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 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);//将保存的信息类初始游戏
//TODO: 提示存档不存在或为空,读取成功 }
else
{
//TODO: 提示存档不存在或为空,读取失败
}
}

存储效果:

<save name="saveFile1">
<target>
<targetPosition>0</targetPosition>
<monsterType>1</monsterType>
</target>
<target>
<targetPosition>1</targetPosition>
<monsterType>3</monsterType>
</target>
<target>
<targetPosition>3</targetPosition>
<monsterType>3</monsterType>
</target>
<target>
<targetPosition>4</targetPosition>
<monsterType>0</monsterType>
</target>
<target>
<targetPosition>6</targetPosition>
<monsterType>3</monsterType>
</target>
<target>
<targetPosition>7</targetPosition>
<monsterType>0</monsterType>
</target>
<shootNum>50</shootNum>
<score>29</score>
</save>
  1. 三种存储方式的对比
  • 二进制方法:简单,但可读性差。
  • XML:可读性强,但是文件庞大,冗余信息多。
  • JSON:数据格式比较简单,易于读写,但是不直观,可读性比XML差。
  1. 本地存储位置补充--关于Application.dataPath

Save&Load--Unity存档读档的学习总结的更多相关文章

  1. Unity - 存读档机制简析

    本文旨在于简要分析Unity中的两种存档机制,即:PlayerPrefs数据持久化方法及Serialization数据序列化方法 较比与源项目,我另加了JSON方法.XML方法等及一些Unity设置, ...

  2. 【UE4 C++】 SaveGame 存档/读档

    创建 SaveGame 类 继承自 USaveGame UCLASS() class TIPS_API USimpleSaveGame : public USaveGame { GENERATED_B ...

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

    此文内容源自siki学院视频,仅供学习!视频链接地址:http://www.sikiedu.com/course/129 工程使用Unity 2017.3.0f3 (64-bit) 老司机读博客,了解 ...

  4. Unity3D — —存读档【转载】

    详细可参考此篇博文: Unity序列化之XML,JSON--------合成与解析 简单例子(SiKi学院教程): using System.Collections; using System.Col ...

  5. 读Flask源代码学习Python--config原理

    读Flask源代码学习Python--config原理 个人学习笔记,水平有限.如果理解错误的地方,请大家指出来,谢谢!第一次写文章,发现好累--!. 起因   莫名其妙在第一份工作中使用了从来没有接 ...

  6. OpenGL——外部读档+异常报错

    从外部读取shader文件: 先添加Shader类: 再创建vertexSource.txt和fragmentSource.txt两个文件: 如图填入shader: 在shader.h宣告: 在sha ...

  7. webpack搭建vue项目开发环境【文档向学习】

    为何有这篇文章 各个社区已经有无数篇帖子介绍如何使用webpack搭建前端项目,但无论是出于学习webpack的目的还是为了解决工作实际需要都面临着一个现实问题,那就是版本更新.别人的帖子可能刚写好版 ...

  8. 【未解决】CImage::Save / Load 导致“线程 0xc224 已退出,返回值为 1 (0x1)”

    不知道这个返回值意味着什么,反正只要用到Save/Load就会出现这个情况. 这个链接:http://forums.codeguru.com/showthread.php?354017-The-thr ...

  9. 从官方文档去学习之FreeMarker

    一.前言 上一篇 <从现在开始,试着学会用官方文档去学习一个技术框架>提倡大家多去从官方文档学习技术,没有讲到具体的实践,本篇就拿一个案例具体的说一说,就是FreeMarker,选择这个框 ...

随机推荐

  1. PHP识别简单的图片上面的数字(可扩展)

    1.场景 最近在学习图片处理,就是特意把数字生成一个图片,然后再用程序去识别图片的数字.这就有了一下的学习过程. 2.原理分析 2.1 首先是将图片像素化,二值化,然后和字模去对比(需要相对于配置字模 ...

  2. CentOS7下使用SonatypeNexus3搭建Docker私有仓库

    前置条件:安装docker(如果机器上没有安装的话) //安装一些必要的系统工具: sudo yum install -y yum-utils device-mapper-persistent-dat ...

  3. 牛客Wannafly挑战赛23 B.游戏

    游戏 题目描述 小N和小O在玩游戏.他们面前放了n堆石子,第i堆石子一开始有ci颗石头.他们轮流从某堆石子中取石子,不能不取.最后无法操作的人就输了这个游戏.但他们觉得这样玩太无聊了,更新了一下规则. ...

  4. CodeM 美团资格赛 思维 dfs

    链接:https://www.nowcoder.com/acm/contest/138/C来源:牛客网 世界杯就要开始啦!真真正正的战斗从淘汰赛开始,现在我们给出球队之间的胜负概率,来预测每支球队夺冠 ...

  5. 三个小白是如何在三个月内搭一个基于kaldi的嵌入式在线语音识别系统的

    前面的博客里说过最近几个月我从传统语音(语音通信)切到了智能语音(语音识别).刚开始是学语音识别领域的基础知识,学了后把自己学到的写了PPT给组内同学做了presentation(语音识别传统方法(G ...

  6. 深入理解 ThreadLocal

    前言 上篇文章 深入理解 Handler 消息机制 中提到了获取线程的 Looper 是通过 ThreadLocal 来实现的: public static @Nullable Looper myLo ...

  7. VUE中CSS样式穿透

    VUE中CSS样式穿透 1. 问题由来 在做两款H5的APP项目,前期采用微信官方推荐的weui组件库.后来因呈现的效果不理想,组件不丰富,最终项目完成后全部升级采用了有赞开发的vant组件库.同时将 ...

  8. Linux入门基础之 中

    五.Linux 下获取帮助 没必要记住所有东西 Linux 提供了极为详细的帮助工具及文档,一定要养成查帮助文档的习惯,可以大大减少需要记忆的东西并且提高效率 5.1.HELP 几乎所有命令都可以使用 ...

  9. idea中applicationContext-dao.xml文件中Cannot resolve file***** :spring xml model validation问题

    访问不了classpath下的文件夹中的文件 解决办法如下:(问题出在我创建的resources文件夹是一个普通的文件夹) 1.本来是普通的文件夹 2.ctrl+shift+alt+s打开如下界面: ...

  10. Android如何管理sqlite

    Android中使用SQlite进行数据操作 标签: sqliteandroid数据库sqlintegerstring 2012-02-28 14:21 8339人阅读 评论(2) 举报  分类: a ...