使用序列化存储游戏数据,方便将对象从一个地方移动到另一个地方(转移文件再反序列化读取)使游戏数据不容易被直接篡改。
二进制方法:简单,但可读性差。
XML:可读性强,但是文件庞大,冗余信息多。
JSON:数据格式比较简单,易于读写,但是不直观,可读性比XML差。
首先我们创建一个名为Save的脚本:
using UnityEngine;
using System.Collections;
[System.Serializable]//序列化
public class Save{
public int score = 0;
}
其次我们创建一个名为GameManager的脚本来读取和修改数据:
using UnityEngine;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
private int localScore;
private Save CreateSaveGO(){
//创建Save对象并存储当前游戏状态信息
Save save = new Save();
//把score保存在Save对象中
save.score = localScore;
//返回该Save对象
return Save;
}
//通过读档信息加载游戏状态
private void SetGame(Save save){
//读取游戏状态信息
localScore = save.score;
}
}
最后我们使用三种存储方法对游戏进行保存与加载。
一、二进制方法:存档与读档
命名空间:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
private void SaveByBin(){
//序列化过程(将Save对象转换为字节流)
//创建Save对象并保存当前游戏状态
Save save = CreateSaveGO();
//创建一个二进制格式化程序
BinaryFormatter bf = new BinaryFormatter();
//创建一个文件流(其中"/StreamingFile"指的是在Unity Project下的Assets资源文件夹中创建的StreamingFile文件夹)
FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile" + "/byBin.txt");
//用二进制格式化程序的序列化方法来序列化Save对象,参数:创建的文件流和需要序列化的对象
bf.Serialize(fileStream,save);
//关闭流
fileStream.Close();
//如果文件存在,则显示保存成功
if(File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
{
Debug.Log("保存成功");
}
}
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);
Debug.Log("加载成功");
}else{
Debug.Log("存档文件不存在");
}
}
二、XML:存档与读档
命名空间:
using System.Xml;
private void SaveByXml(){
Save save = CreatSaveGO();
//创建XML文件的存储路径(其中"/StreamingFile"指的是在Unity Project下的Assets资源文件夹中创建的StreamingFile文件夹)
string filePath = Application.dataPath + "/StreamingFile" + "/byXML.txt";
//创建XML文档
XmlDocument xmlDoc = new XmlDocument();
//创建根节点,即最上层节点
XmlElement root = xmlDoc.CreateElement("save");
//设置根节点中的值
root.SetAttribute("name","saveFile1");
//创建XmlElement
XmlElement score = xmlDoc.CreateElement("score");
//设置InnerText值并设置层级关系(xmlDoc -- root -- score)
score.InnerText = save.score.ToString();
root.AppendChild(score);
xmlDoc.AppendChild(root);
xmlDoc.Save(filePath);
if(File.Exists(Application.dataPath + "/StreamingFile" + "/byXML.txt"))
{
Debug.Log("保存成功");
}
}
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 score = xmlDoc.GetElementsByTagName("score");
int scoreCount = int.Parse(score[0].InnerText);
save.score = scoreCount;
SetGame(save);
Debug.Log("加载成功");
}else{
Debug.Log("存档文件不存在");
}
}
三、Json:存档与读档
命名空间:
using LitJson;
private void SaveByJson(){
Save save = CreateSave();
//"/StreamingFile"指的是在Unity Project下的Assets资源文件夹中创建的StreamingFile文件夹,存储的文件可以是json格式也可是txt格式
string filePath = Application.dataPath + "/StreamingFile" + "/byJson.json";
//利用JsonMapper将save对象转换为Json格式的字符串
string saveJsonStr = JsonMapper.ToJson(save);
//将字符串写入到文件中
//创建一个StreamWriter,并将字符串写入文件中
StreamWriter sw = new StreamWriter(filePath);
sw.Write(saveJsonStr);
//关闭StreamWrite
sw.Close();
Debug.Log("保存成功");
}
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);
Debug.Log("加载成功");
}else{
Debug.Log("存档文件不存在");
}
}
备注:利用Json对数据进行存档读档前需要将Json的库放进Unity Project下的Assets资源文件夹中。
拓展:
一、Using 自动释放流
除了用Close关闭流文件外可以用using自动释放流:
try {
BinaryFormatter bf=new BinaryFormatter();
using(FileStream fs=File.Create(Application.persistentDataPath+"/GameData.data")){
//使用using可以自动释放流
//将类的数据序列化写进本地
}
} catch (System.Exception ex) {
Debug.Log (ex.Message);
}
二、PlayerPrefs 数据持久化
PlayerPrefs用于本地持久化保存与读取的类,工作原理很简单,以键值对的形式将数据保存在文件中,然后程序可以根据这个名称取出上次保存的数值(注:数据通过键名来读取,当值不存在时,返回默认值)。
Playerprefs类支持3种数据类型的保存和读取,分别是浮点型、整型和字符串型:
PlayerPrefs.SetInt();保存整型数据
PlayerPrefs.SetFloat();保存浮点型数据
PlayerPrefs.SetString();保存字符串型数据
PlayerPrefs.GetInt();读取整型数据
PlayerPrefs.GetFloat();读取浮点型数据
PlayerPrefs.GetString();读取字符串型数据
例子(对游戏内背景音乐是否开启进行存储):
public Toggle musicToggle;
public AudioSource musicAudio;
private void Awake(){
if(PlayerPrefs.HasKey("MusicOn")){
if(PlayerPrefs.GetInt("MusicOn") == 1){
musicToggle.isOn = true;
musicAudio.enable = true;
}else{
musicToggle.isOn = false;
musicAudio.enable = false;
}
}else{
musicToggle.isOn = true;
musicAudio.enable = true;
}
}
public void MusicSwitch(){
//通过判断单选框是否被勾选上,从而决定是否播放背景音乐
if(musicToggle.isOn == false){
musicAudio.enable == false;
//保存音乐开关的状态,0代表关闭状态
PlayerPrefs.SetInt("MusicOn",0);
}else{
musicAudio.enable = true;
PlayerPrefs.SetInt("MusicOn",1);
}
PlayerPrefs.Save();//对数据进行存储
}