存檔與讀檔功能
舉例:
-
傳統RPG游戲(仙劍、空之軌跡):
1.角色信息(生命值,等級)
2.道具信息(裝備,葯品)
3.場景信息(場景名稱、角色坐標)
4.事件信息(任務相關) -
關卡類游戲:關卡的通關情況
-
一些特殊的存檔機制(漫漫長夜、億萬僵屍)
Unity中使用的存檔方式
一、PlayerPrefs:數據持久化方案
-
原理:采用鍵值對的方式對數據進行存儲---保存在本地文件(不同操作系統存儲路徑不同)中,然后程序可以根據這個名稱取出上次保存的數值)
-
儲存類型:可以存儲Int, Float, String類型的數據。
-
使用例子
//存儲數據:
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;
}
- 二進制存儲(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: 提示存檔不存在或為空,讀取失敗
}
}
- 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
}
- XML存儲
XML:擴展標記語言,用於標記電子文件使其具有結構性的標記語言。
- 可以用來標記數據、定義數據類型。
- 序列化與反序列化的方式與二進制方法十分類似。
//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>
- 三種存儲方式的對比
- 二進制方法:簡單,但可讀性差。
- XML:可讀性強,但是文件龐大,冗余信息多。
- JSON:數據格式比較簡單,易於讀寫,但是不直觀,可讀性比XML差。
- 本地存儲位置補充--關於Application.dataPath
- 編輯模式下為Assets文件夾,其他:
Unity3D各平台Application.dataPath的路徑