Unity存储简介
Unity保存数据分为二进制、Json、Xml、Excel等方式,还有一个Unity缓存方法。
将游戏数据存储起来,实现读档功能
数据保存时和读取时需要设专门的类
对类里面的变量进行读取和赋值达到读档、存档功能。
Unity缓存方法
Unity通过PlayerPrefs,通过键值对的方式存储,只能存储只能存储int,float,string这三种数据类型,扩展方式强
存储时:
if (MusicToggle.isOn==false)
{
MusicAudioSource.enabled = false;
PlayerPrefs.SetInt("MusicOn",0);
}
else
{
MusicAudioSource.enabled = true;
PlayerPrefs.SetInt("MusicOn",1);
}
PlayerPrefs.Save();
读取时:
if (PlayerPrefs.HasKey("MusicOn"))
{
if (PlayerPrefs.GetInt("MusicOn")==1)
{
MusicToggle.isOn = true;
}
else
{
MusicToggle.isOn = false;
}
}
具体在参考文档:
https://docs.unity.cn/cn/current/ScriptReference/PlayerPrefs.html
游戏数据存储
首先,创建一个类去存储和读取数据
public class Save
{
public List<int> livingTargetPositions = new List<int>();
public List<int> livingMonsterTypes = new List<int>();
public int shootTimes = 0;
public int score = 0;
}
将要保存的游戏数据存进类中
private Save CreatSaveGO()
{
Save save = new Save();
foreach (var target in targets)
{
TargetManager targetManager = target.GetComponent<TargetManager>();
if (targetManager.activeMonster != null)
{
save.livingTargetPositions.Add(targetManager.targetPosition);
int type = targetManager.activeMonster.GetComponent<MonsterManager>().monsterType;
save.livingMonsterTypes.Add(type);
}
}
save.shootTimes = UIManager._instance.shoottimes;
save.score = UIManager._instance.score;
return save;
}
二进制方法
游戏管理的脚本添加引用
using System.Runtime.Serialization.Formatters.Binary;
C#自带的,将数据以二进制的格式存储
private void SaveByBin()
{
//序列化过程,创建Save对象并保存当前游戏状态
Save save = CreatSaveGO();
//创建一个二进制格式化程序
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("存档文件不存在!");
}
}
Json存储
Json方式存储,需要先在NuGet包获取LitJson包
获取之后到工程文件里找
根据自己工程的PlayerSetting选择
将这个文件拖进工程里
然后开始在脚本里添加引用:using LitJson;
private void SaveByJson()
{
Save save = CreatSaveGO();
string filePath = Application.dataPath + "/StreamingFile" + "/ByJson.json";
//利用JsonMapper将save对象转换为Json格式的字符串
string saveJsonStr = JsonMapper.ToJson(save);
//将这个字符串写入到文件中
//创建一个StreamingWriter
StreamWriter sw = new StreamWriter(filePath);
sw.Write(saveJsonStr);
//关闭StreamWriter
sw.Close();
UIManager._instance.ShowMessage("保存成功!");
}
关于第三方库
LitJson默认是Unicode编码方式,所以存储中文是\uXXXX类型的
这个函数的作用是把正则表达式表示的字符串转换成非正则表达式的字符串
所以,如果存储的数据包含中文,则需要添加引用:using System.Text.RegularExpressions;
将string saveJsonStr = JsonMapper.ToJson(save); 改为 string saveJsonStr=Regex.Unescape(JsonMapper.ToJson(save));
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);//jsonStr为文件的内容转换成了字符串,这里需要将字符串转换成目标对象
SetGame(save);
UIManager._instance.ShowMessage("");
}
else
{
UIManager._instance.ShowMessage("存档文件不存在!");
}
}
File.Exists(filePath) 用来判断的文件是否存在
Xml存储
Xml存储运用的是C#自带的库
添加引用using System.Xml;
Xml文件创建方式不像以上方法简便,需要手动添加根节点、子节点
例子中每个节点作为一个target进行存储
private void SaveByXml()
{
Save save = CreatSaveGO();
//创建XML文件的存储路径
string filePath = Application.dataPath + "/StreamingFile" + "/ByXml.txt";
//创建XML文档
XmlDocument xmlDocument = new XmlDocument();
//创建根节点,即最上层节点
XmlElement root = xmlDocument.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 = xmlDocument.CreateElement("target");
targetPosition = xmlDocument.CreateElement("targetPosition");
targetPosition.InnerText = save.livingTargetPositions[i].ToString();
monsterType = xmlDocument.CreateElement("monsterType");
monsterType.InnerText = save.livingMonsterTypes[i].ToString();
//设置节点间的层级关系 root -- target -- (targetPosition, monsterType)
target.AppendChild(targetPosition);
target.AppendChild(monsterType);
root.AppendChild(target);
}
XmlElement shootTimes = xmlDocument.CreateElement("shootTimes");
shootTimes.InnerText = save.shootTimes.ToString();
XmlElement score = xmlDocument.CreateElement("score");
score.InnerText = save.score.ToString();
root.AppendChild(shootTimes);
root.AppendChild(score);
xmlDocument.AppendChild(root);
xmlDocument.Save(filePath);
if (File.Exists(Application.dataPath + "/StreamingFile" + "/ByXml.txt"))
{
UIManager._instance.ShowMessage("保存成功!");
}
}
加载Xml文件需要考虑节点的层级关系
读取时将文件数据读成节点列表
遍历节点列表,利用层级关系将属性赋值在游戏物体上
private void LoadByXml()
{
string filePath = Application.dataPath + "/StreamingFile" + "/ByXml.txt";
if (File.Exists(filePath))
{
Save save = new Save();
//加载XML文档
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(filePath);
//通过节点名称来获取元素,结果为XmlNodeList类型
XmlNodeList targets = xmlDocument.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 shoottimes = xmlDocument.GetElementsByTagName("shootTimes");
int shootTimes = int.Parse(shoottimes[0].InnerText);
save.shootTimes = shootTimes;
XmlNodeList Score = xmlDocument.GetElementsByTagName("score");
int score = int.Parse(Score[0].InnerText);
save.score = score;
SetGame(save);
UIManager._instance.ShowMessage("");
}
else
{
UIManager._instance.ShowMessage("存档文件不存在!");
}
}
附上对应的Xml文件参考
<save name="saveFile1">
<target>
<targetPosition>1</targetPosition>
<monsterType>1</monsterType>
</target>
<target>
<targetPosition>3</targetPosition>
<monsterType>3</monsterType>
</target>
<target>
<targetPosition>5</targetPosition>
<monsterType>3</monsterType>
</target>
<target>
<targetPosition>6</targetPosition>
<monsterType>2</monsterType>
</target>
<target>
<targetPosition>7</targetPosition>
<monsterType>3</monsterType>
</target>
<target>
<targetPosition>8</targetPosition>
<monsterType>2</monsterType>
</target>
<shootTimes>7</shootTimes>
<score>4</score>
</save>
读取文件通用步骤
1、获取目标文件的存储路径,定义一个字符串记录目标文件的存储路径+/目标文件的文件名
2、判断在该路径下能否找到目标文件
3、倘若找到,创建文件流对象读取文件里的信息
4、根据文件的类型进行转换,例如:二进制文件转换成字节数组,Json文件转换成字符串
5、根据获取的数据创建对应的数据类型,进行解析存储,针对有的数据类型可以为空,需要将此类型定义为数组或列表
6、看文件是否有对应的协议,例如:文件的头部信息、数据的进制转换,再进行解析
附上解析bin文件的例子
此文件的头部信息是:1个byte存储版本号、1个int类型存储该文件里点云数据的点的个数、1个bool类型存储该文件是否包含颜色信息、接下来是点数据(3个float记录点的坐标x、y、z、3个float记录点的颜色r、g、b)
private void LoadByBin()
{
//如果该二进制文件存在的话
if (File.Exists(Application.dataPath + "/#3_pile.bin"))
{
//Debug.Log("yes");
FileStream fs = new FileStream(path, FileMode.Open);
BinaryReader br = new BinaryReader(fs);
byte b=br.ReadByte();
int l = br.ReadInt32();
Debug.Log(b);
Debug.Log(l);
bool color=br.ReadBoolean();
for(int i=0; i < l; i++)
{
Point p=new Point();
p.x=br.ReadSingle();
p.y= br.ReadSingle();
p.z= br.ReadSingle();
p.r = br.ReadSingle();
p.g = br.ReadSingle();
p.b = br.ReadSingle();
points.Add(p);
}
br.Close();
fs.Close();
}
else
{
Debug.Log("no");
}
}