存档与读档功能

举例:

  • 传统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. JDBC之PreparedStatement

    JDBC之PreparedStatement 一.java.sql.PreparedStatement接口简介 该接口表示预编译的 SQL 语句的对象. SQL 语句被预编译并存储在 Prepared ...

  2. java四种引用及在LeakCanery中应用

    java 四种引用 Java4种引用的级别由高到低依次为: StrongReference > SoftReference > WeakReference > PhantomRefe ...

  3. 第8章 浏览器对象模型BOM 8.1 window对象

    ECMAScript是javascript的核心,但如果要在web中使用javascript,那么BOM(浏览器对象模型)则无疑是真正的核心.BOM提供了很多对象,用于访问浏览器的功能,在浏览器之间共 ...

  4. hdu 5977 Garden of Eden(点分治+状压)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5977 题解:这题一看就知道是状压dp然后看了一下很像是点分治(有点明显)然后就是简单的点分治+状压dp ...

  5. 1 PY环境与变量

    一 环境与文件形式 1.环境搭建http://jingyan.baidu.com/article/eae07827f7f2d01fec5485f7.html 2. python 则进入交互模式  ex ...

  6. Java之多线程(一)

    一,前言 ​ 今天总结一些关于线程方面的知识,说到线程可谓是无人不知,毕竟这东西不管是在工作开发中,还是实际生活中都时时存在着.关于线程方面的内容非常多,从简单的单线程,多线程,线程安全以及到高并发等 ...

  7. python 整型、字符串常用方法、for循环

    整型--int 定义:用于比较和计算 python2和python3: python2:python2中油int(整型)和long(长整型):1231312L+ 进制转换: 十进制转二进制:正除2,获 ...

  8. 使用Nginx、Nginx Plus防止服务器DDoS攻击

    分布式拒绝服务攻击(DDoS)指的是通过多台机器向一个服务或者网站发送大量看似合法的数据包使其网络阻塞.资源耗尽从而不能为正常用户提供正常服务的攻击手段.随着互联网带宽的增加和相关工具的不断发布,这种 ...

  9. 使用 jupyter-notebook + python + matplotlib 进行数据可视化

    上次用 python 脚本中定期查询数据库,监视订单变化,将时间与处理完成订单的数量进行输入写入日志,虽然省掉了人为定时查看数据库并记录的操作,但是数据不进行分析只是数据,要让数据活起来! 为了方便看 ...

  10. CentOS 磁盘扩容

    本人对Linux本来就不是很熟,但是由于各种原因开始捣鼓CentOS(大家都说是这个系统比较好学),开始预计20G的磁盘就足够了,没想到装Oracle就直接报磁盘空间不足,更别提在Tomcat下部署近 ...