Unity中常用的游戏存档/读档技术
1.PlayerPrefs:是Unity提供的一个用于本地持久化保存与读取的类,是以键值对的形式将数据写入到注册表中,并且可以提供方法来按照键来取出对应的值应用到游戏中,适用于保存较为简单的游戏数据。对应的方法如下:
PlayerPrefs.SetInt(string key,int value);//保存int型的值
PlayerPrefs.GetInt(string key);//获取保存的int型值。
PlayerPrefs.SetFloat(string key,float value);//保存float型的值
PlayerPrefs.GetFloat(string key);//获取保存的float型值。
PlayerPrefs.SetString(string key,string value);//保存string型的值
PlayerPrefs.GetString(string key);//获取保存的string型值。
当去获取的值在注册表中并不存在的时候,会返回默认值!
除了以上的方法以外,还提供了PlayerPrefs.DeleteKey(string key)来删除对应的键值,还有PlayerPrefs.DeleteAll();来删除所有的键值。
应用场景:
以下的三种方式是我应用在我的打地鼠游戏中的存取方式,主要用来保存地鼠出现的位置(0-8)以及地鼠的类型(0-3),以及击打的次数和得分等等信息。
2.二进制数据存取方法:将游戏对象序列化为二进制数据流进行传输和存储,当需要使用的时候将数据流反序列化为游戏对象即可。在对游戏对象进行序列化的时候,需要在类前声明[System.Serializable]证明是可序列化的。执行存档以后会在指定路径下生成一个txt文件,但是由于是数据流,可读性很差。主要的核心代码如下:
二进制存档:
///二进制存档
private void SaveByBin()
{
Save save = GetSaveInfo();//先将需要存档的游戏信息读取过来并保存起来
BinaryFormatter bf = new BinaryFormatter();//创建一个二进制格式化程序
FileStream fileStream = File.Create(Application.dataPath + "/StreamingFiles" + "/Bin.txt");//创建一个文件流
bf.Serialize(fileStream, save);//利用二进制格式化程序的序列化方法来序列化save对象,参数:创建的文件流和需要序列化的对象
fileStream.Close(); //关闭流
if (File.Exists(Application.dataPath + "/StreamingFiles" + "/Bin.txt"))
{
ShowMessage("保存成功!");
}
}
二进制存档:
private void LoadByBin()//加载游戏就是一个反序列化的过程
{
if (File.Exists(Application.dataPath + "/StreamingFiles" + "/Bin.txt"))
{
BinaryFormatter bf = new BinaryFormatter();//创建一个二进制格式化程序
FileStream fileStream = File.Open(Application.dataPath + "/StreamingFiles" + "/Bin.txt", FileMode.Open);//打开数据流
Save save = (Save)bf.Deserialize(fileStream);//调用二进制格式化程序中的反序列化方法,将数据流反序列化为save对象并进行保存
fileStream.Close();//关闭文件流
SetGame(save);//反序列化之后得到的对象再传入到SetGame()中,设置游戏数据
ShowMessage("");
}
else
{
ShowMessage("文件不存在,加载失败!!!");
Debug.Log("加载失败!!");
}
}
效果图如下:
3.Json数据存取:Json是将游戏对象转换成字符串形式并且写入到指定路径下的json文档中来进行存储的,当需要的时候又将字符串转换成游戏对象。字符串和游戏对象之间的转换需要导入并且引用库文件using LitJson;,同时也对文件的读写进行了操作,所以也要引入命名空间using System.IO;,最后生成的文件可读性比二进制的高。
具体实现代码如下:
Json存档:
private void SaveByJson()
{
//using LitJson;下载导入并引入库LitJson
Save save = GetSaveInfo();//依旧使用对象来接收需要保存的游戏数据
string filePath = Application.dataPath + "/StreamingFiles" + "/Json.json";//创建路径
string saveJsonStr = JsonMapper.ToJson(save);//利用JsonMapper将save对象转换成Json格式的字符串
//将字符串写入到文件中
//创建一个StreamWriter,调用其中的方法来将字符串写入到文件中
StreamWriter sw = new StreamWriter(filePath);
sw.Write(saveJsonStr);//写入到创建好的文件中,调用文件的读写函数需要引入命名空间using System.IO;
sw.Close();//关闭StreamWriter
if (File.Exists(Application.dataPath + "/StreamingFiles" + "/Json.json"))
{
ShowMessage("Json保存成功!!!");
}
else
{
ShowMessage("Json文件保存失败!!");
}
}
Json读档:
private void LoadByJson()
{
string filePath = Application.dataPath + "/StreamingFiles" + "/Json.json";//首先先获得保存好的Json文件的路径
if (File.Exists(filePath))//有文件才开始读档
{
StreamReader streamReader = new StreamReader(filePath);//创建一个读取的StreamWrite用来读取文档的内容
string jsonStr = streamReader.ReadToEnd();//将文件流读取到末尾用字符串进行存储
streamReader.Close();//读取完毕之后就关闭流
Save save = JsonMapper.ToObject<Save>(jsonStr);//在读取完毕之后就调用JsonMapper中的函数叫读取的字符串转换成对象
SetGame(save);//将获得的对象传入设置游戏的函数
ShowMessage("");
}
else
{
ShowMessage("文件不存在,读档失败!");
}
}
效果图如下:
4.XML数据存取:XML这种存储方式是一种节点存储方式,其格式很像html,将得到的对象数据分解存到不同的节点的innerText属性中,然后再设置每一个节点的之间的层级关系,最后存入到文件中,文件的可读性非常好。具体的操作流程如下:
1.引入Using System.XML命名空间,利用XmlDocument创建Xml文档。
2.创建节点,并根据获取的游戏对象的值来设置节点的innerText的值。
3.设置节点之间的层级关系,然后保存文件即可。
取出文件时反之即可!
具体实现代码如下:
XML存档:
private void SaveByXml()
{
Save save = GetSaveInfo();//先获取需要保存的对象
string filePath = Application.dataPath + "/StreamingFiles" + "/XML.txt";//设置文件保存的路径,并且引入命名空间Using System.XML
XmlDocument xmlDoc = new XmlDocument();//创建XML文档
//创建根节点,即最上层的节点
XmlElement root = xmlDoc.CreateElement("save");
//设置根节点中的值
root.SetAttribute("name", "saveFileXML");
//通过target中的怪物的位置和种类来定义和设置文档中的元素,进行规范存储
XmlElement Target;
XmlElement TargetPosition;
XmlElement MonsterType;
for (int i = 0; i < save.monstersPositionList.Count; i++)
{
//创建节点
Target = xmlDoc.CreateElement("Target");
TargetPosition = xmlDoc.CreateElement("TargetPosition");
MonsterType = xmlDoc.CreateElement("MonsterType");
//设置节点中的内容,并且设置好父节点 层级关系为root--Target-(TargetPosition,MonsterType);
TargetPosition.InnerText = save.monstersPositionList[i].ToString();//设置位置的文本值
Target.AppendChild(TargetPosition);//设置根节点关系,TargetPosition是Target的子孩子
MonsterType.InnerText = save.monstersTypeList[i].ToString();//设置怪物类型的值
Target.AppendChild(MonsterType);//设置根节点的关系,MonsterType是Target的子孩子
//将target也设置为根节点的子孩子
root.AppendChild(Target);
}
//设置设计数量和得分,为root的子孩子
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);
//将root节点设置为文档的初始节点然后将文档保存到指定的路径之中
xmlDoc.AppendChild(root);
xmlDoc.Save(filePath);//将文档保存到指定的路径之中
if (File.Exists(Application.dataPath + "/StreamingFiles" + "/XML.txt"))
{
ShowMessage("XML保存成功!!!");
}
}
XML读档:
private void LoadByXml()
{
string filePath = Application.dataPath + "/StreamingFiles" + "/XML.txt";
if (File.Exists(filePath))
{
Save save = new Save();//创建save对象,用来返回
XmlDocument xmlDoc = new XmlDocument();//创建文本
xmlDoc.Load(filePath);//根据路径读取内容到文本之中
//通过节点来获取元素,结果为XMLLoadList类型
XmlNodeList Targets = xmlDoc.GetElementsByTagName("Target");//根据名字为Target的元素加入到节点列表中
//遍历所有的Target节点,并且获得它的子孩子和子孩子的InnerText
if (Targets.Count!=0)//假如至少有一个的话,表示文档中怪物至少有一个的话,那么就遍历Targets中的所有target
{
foreach (XmlNode Target in Targets)
{
//存放位置信息
XmlNode TargetPosition = Target.ChildNodes[0];//节点的第一个子孩子为位置,第二个子孩子为怪物的类型
save.monstersPositionList.Add(int.Parse(TargetPosition.InnerText));//在列表中就存入了位置信息
//存放怪物的类型
XmlNode MonsterType = Target.ChildNodes[1];
save.monstersTypeList.Add(int.Parse(MonsterType.InnerText));
}
}
//设置射击数和得分
save.shootNum =int.Parse( xmlDoc.GetElementsByTagName("ShootNum")[0].InnerText);
save.score = int.Parse(xmlDoc.GetElementsByTagName("Score")[0].InnerText);
SetGame(save);
}
else
{
ShowMessage("XML文件不存在,加载失败!!!");
}
}
效果图如下:
总结:
几种存取方式都有自己的独特点。如果有不足之处希望各位大佬评论指正!