存档与读档功能

举例:

  • 传统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. Javabean及其在jsp中的应用

    Javabean及其在jsp中的应用 一.Javabean简介 用作JavaBean的类必须具有一个公共的.无参数的构造方法. JavaBean的属性与普通Java类的属性的概念不一样,JavaBea ...

  2. Spring框架入门之基于Java注解配置bean

    Spring框架入门之基于Java注解配置bean 一.Spring bean配置常用的注解 常用的有四个注解 Controller: 用于控制器的注解 Service : 用于service的注解 ...

  3. 基于JRebel开发的MySQL Explain插件

    前言 我们在使用数据库时,为了使业务系统性能达到最优,往往都需要避免慢SQL查询,不能等到线上告警了再排查是否为慢SQL导致.在开发阶段,每个开发人员就应该针对自己写的SQL看是否可能为慢SQL,从而 ...

  4. jasypt

    jasypt-1.9.0.jar import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; public class EncryptUt ...

  5. CodeForces - 632E Thief in a Shop 完全背包

    632E:http://codeforces.com/problemset/problem/632/E 参考:https://blog.csdn.net/qq_21057881/article/det ...

  6. 牛客暑假多校第五场 D inv

    题意:给你一个n, 接来下给你一个 [1,n] 中偶数的排列, 还有一个 [1, n] 中 奇数 按照递增的顺序排列, 现在求一个原数列, 使得偶数列排序 和 奇数列 都是原数列的一个子序列, 现在求 ...

  7. [NOI2009]诗人小G 四边形优化DP

    题目传送门 f[i] = min(f[j] + val(i,j); 其中val(i,j) 满足 四边形dp策略. 代码: #include<bits/stdc++.h> using nam ...

  8. UVA 494 Kindergarten Counting Game map

    Everybody sit down in a circle. Ok. Listen to me carefully.“Woooooo, you scwewy wabbit!”Now, could s ...

  9. hdu1576 扩展欧几里德 A/B

    A/B Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  10. 移动端适配,h5网页,手机端适配兼容方案.可以显示真实的1px边框和12px字体大小,dpr浅析

    以前写移动端都是用这段JS解决. (function (doc, win) { // 分辨率Resolution适配 var docEl = doc.documentElement, resizeEv ...