目录

1 概念2 PlayerPrefs2.1 概念2.2 操作1 存储2 读取3 删除

2.3 Windows存储位置2.4 优缺点分析2.5 自定义类的存储

3 JSON3.1 概念3.2 JsonUtility1 JsonUtility.ToJson2 JsonUtility.FromJson3 JsonUtility.FromJsonOverwrite

3.3 支持/不支持Unity序列化1 字段2 类

3.4 基于Json的简易存档系统3.6 优缺点分析

4 XML4.1 概念4.2 基于XML的简易存档系统

这一篇只能说写了一部分,并没有把Unity里数据持久化的操作讲完整,之后可能是学到一点就记一点的模式。

1 概念

数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。

人话版:将游戏数据存储到硬盘,硬盘中数据读取到游戏中,也就是传统意义上的存盘。

2 PlayerPrefs

2.1 概念

PlayerPrefs是Unity提供的一个可以用于存储读取玩家数据的公共类。

2.2 操作

1 存储

PlayerPrefs的数据存储类似于键值对,一个键对应一个值。它提供了3种数据存储方式:int,float,string。

键:string。 值:int,float,string,对应3种API。

PlayerPrefs.SetInt("Age", 18);

PlayerPrefs.SetFloat("Height", 100);

PlayerPrefs.SetString("Name", ",manqi");

需要注意的是,直接调用API只会把数据存储到内存中。当游戏结束时,才会自动把数据存到硬盘中。

如果游戏不是正常结束(崩溃等),数据是不会存到硬盘中的。为了能立刻将数据存储到硬盘中,避免丢失的情况,我们可以用PlayerPrefs.Save()。

PlayerPrefs.Save(); //将数据立刻存储到硬盘中

然而我们可以看到PlayerPrefs是有局限性的,它只能存储3种类型的数据,如果有其他类型需求,只能降低精度或者转变类型(如bool的true存储为int的1)。

另外,需要注意,如果同一键名存储,无论数据类型是否变化,都会将原来的数据覆盖。(所以我们要保证key的唯一性。

PlayerPrefs.SetInt("Age",18);

PlayerPrefs.SetString("Age","18");

2 读取

用int举例:

//如果没有对应键,会传出默认值,如int-0。

int age = PlayerPrefs.GetInt("Age");

//如果找不到对应键,会传出函数第二个参数。

int age = PlayerPrefs.GetInt("Age",100);

判断数据是否存在:

if(PlayerPrefs.HasKey("Age")){

print("存在");

}

3 删除

//删除指定键值对

PlayerPrefs.DeleteKey("Age");

PlayerPrefs.DeleteAll();

2.3 Windows存储位置

PlayerPrefs存储在HKEY_CURRENT_USER\Software[公司名][产品名] 项下的注册表中。(其中公司名和产品名是“File->Build Setting->Project Settings->Player”中设置的名称。

但我们会发现,当我们直接修改注册表内数据信息时,游戏内读取到的数据也会对应改变,这是用PlayerPrefs存储信息的缺陷。针对这个缺陷,我们可以进行加密或者是采取其他的数据存储方式。

2.4 优缺点分析

优点:简单易懂方便操作。 缺点:①能直接存储的数据类型有限,复杂类型的存储需要自己实现;②数据安全性低,容易被修改。 适用范围:适合用来存储暂时性数据,如玩家偏好设定。

2.5 自定义类的存储

自定义类的存储我们可以利用PlayerPrefs的SetString API以及JsonUtility。

方法类

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public static class SaveSystem{

public static void SaveByPlayerPrefs(string key,object data) {

var json = JsonUtility.ToJson(data);

PlayerPrefs.SetString(key, json);

PlayerPrefs.Save();

}

public static string LoadFromPlayerPrefs(string key) {

return PlayerPrefs.GetString(key, null) ;

}

}

调用类

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Test : MonoBehaviour {

//增加可序列化特性才能被JsonUtility转换

[System.Serializable]

class SaveData {

public string playerName;

public string playerLevel;

public string playerCoin;

public Vector3 playerPosition;

}

const string PLAYER_DATA_KEY = "PlayerData";

public string playerName;

public string playerLevel;

public string playerCoin;

public Vector3 playerPosition;

//存档

SaveData SavingData() {

var savaData = new SaveData();

savaData.playerName = playerName;

savaData.playerLevel = playerLevel;

savaData.playerCoin = playerCoin;

savaData.playerPosition = playerPosition;

return savaData;

}

void SaveByPlayerPrefs() {

SaveSystem.SaveByPlayerPrefs(PLAYER_DATA_KEY, SavingData());

}

//读档

void LoadFromPlayerPrefs() {

var json = SaveSystem.LoadFromPlayerPrefs(PLAYER_DATA_KEY);

var saveData = JsonUtility.FromJson(json);

}

void LoadData(SaveData saveData) {

playerName = saveData.playerName;

playerLevel = saveData.playerLevel;

playerName = saveData.playerName;

playerPosition = saveData.playerPosition;

}

//删除

void DeletePlayerDataPrefs() {

PlayerPrefs.DeleteKey(PLAYER_DATA_KEY);

}

}

3 JSON

3.1 概念

在Unity中,JSON(JavaScript Object Notation)是一种常见的数据交换格式。Unity内置了JsonUtility类,可以用于将对象序列化为JSON字符串或将JSON字符串反序列化为对象。

3.2 JsonUtility

JsonUtility是Unity内用来处理Json数据的类,相关API:JsonUtility

1 JsonUtility.ToJson

第一个参数必须支持Unity序列化,具体是否能被序列化见【3.3】。 第二个参数指的是是否转换为更适合阅读的Json文本格式。

var json = JsonUtility.ToJson(object);

var json = JsonUtility.ToJson(object,bool);

另外,需要注意的是,如果data为空:

bool data;

print(JsonUtility.ToJson(data));

此时控制台只会打印出一个{},因为Json序列化的对象是数据本身,而data本身没有存储任何数据,此时Json会尝试序列化,但它会发现序列化的内容为空,因此只会打印出一个{}。

如果我们希望Json能正确转换字段,我们可以直接转换封装的类本身。

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ToJsonTest : MonoBehaviour{

[System.Serializable] class Player {

public string playerName;

public bool isDie;

public int health;

}

void Start(){

Player player = new Player();

print(JsonUtility.ToJson(player));

}

}

2 JsonUtility.FromJson

public static T FromJson(string json);

3 JsonUtility.FromJsonOverwrite

转换后的数据覆盖第二个参数传入的object。

public static void FromJsonOverwrite(string json,object objectToOverwrite);

3.3 支持/不支持Unity序列化

简单的判断是否能被Unity序列化的方法: 将类型标记为public或者在前面标上[SerializeField]特性,看该类型是否能在Inspector窗口显示。 PS:JsonUtility类只支持序列化和反序列化C#对象,不支持序列化和反序列化Unity的组件和对象。

具体的:

1 字段

2 类

3.4 基于Json的简易存档系统

方法类

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System.IO;

public static class SaveSystem{

public static void SaveByJson(string saveFileName,object data) {

var json = JsonUtility.ToJson(data);

//Application.persistentDataPath:Unity提供的一个存储永久数据的路径:不同平台上路径不同。

//Path.Combine:合并传入的路径。

var path = Path.Combine(Application.persistentDataPath, saveFileName) ;

//File.WriteAllText方法用于写入字符串类型的数据,而Json是字符串类型。

File.WriteAllText(path, json);

}

public static T LoadFromJson(string saveFileName) {

var path = Path.Combine(Application.persistentDataPath, saveFileName);

var json = File.ReadAllText(path);

var data = JsonUtility.FromJson(json);

return data;

}

public static void DeleteSaveFile(string saveFileName) {

var path = Path.Combine(Application.persistentDataPath, saveFileName);

File.Delete(path);

}

}

调用类

using System.Collections;

using System.Collections.Generic;

using Unity.VisualScripting;

using UnityEngine;

public class Test : MonoBehaviour{

//增加可序列化特性才能被JsonUtility转换

[System.Serializable]class SaveData {

public string playerName;

public string playerLevel;

public string playerCoin;

public Vector3 playerPosition;

}

const string PLAYER_DATA_KEY = "PlayerData";

const string PLAYER_DATA_FILE_NAME = "PlayerData";

public string playerName;

public string playerLevel;

public string playerCoin;

//存档

SaveData SavingData() {

var saveData = new SaveData();

saveData.playerName = playerName;

saveData.playerLevel = playerLevel;

saveData.playerCoin = playerCoin;

saveData.playerPosition = transform.position;

return saveData;

}

void SaveByJson() {

SaveSystem.SaveByJson(PLAYER_DATA_FILE_NAME, SavingData());

}

//读档

void LoadFromJson() {

var saveData = SaveSystem.LoadFromJson(PLAYER_DATA_FILE_NAME);

LoadData(saveData);

}

void LoadData(SaveData saveData) {

playerName = saveData.playerName;

playerLevel = saveData.playerLevel;

playerCoin = saveData.playerCoin;

transform.position = saveData.playerPosition;

}

//删除

void DeletePlayerDataFiles() {

SaveSystem.DeleteSaveFile(PLAYER_DATA_FILE_NAME);

}

}

3.6 优缺点分析

优点:①更符合人类的阅读习惯;②广泛使用,适用多编程语言;③轻量级,易于网络传输与机器解析和生成。 缺点:①支持的数据类型有限(因为是通过Unity的序列化程序实现的;②数据安全性低。 适用范围: 联网:①优秀的网络数据交换载体;②云存档。 本地存储:①非敏感而需要大量读取和修改的数据,如Mod;②玩家的偏好设置。

4 XML

4.1 概念

在Unity中,XML(Extensible Markup Language)是一种常见的数据交换格式。Unity提供了System.Xml命名空间下的类库,可以用于将XML数据序列化为对象或将对象反序列化为XML数据。

5

man

10

woman

15

woman

4.2 基于XML的简易存档系统

请注意,由于Unity默认不支持使用XmlSerializer类,因此我们需要在Assets文件夹中创建一个空的XML文件夹,并将MonoXml.dll文件从Windows的.NET Framework文件夹中拷贝到该文件夹中。

方法类

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System.IO;

using System.Xml.Serialization;

public static class SaveSystem {

//存储

public static void SaveByXml(string saveFileName, object data) {

//创建XmlSerializer对象,传入待序列化数据的类型。

var serializer = new XmlSerializer(data.GetType());

//创建FileStream对象,指定文件路径和操作模式。

string path = Path.Combine(Application.persistentDataPath, saveFileName);

var stream = new FileStream(path, FileMode.Create);

//序列化数据,并写入文件

serializer.Serialize(stream, data);

stream.Close();

}

//读取

public static T LoadFromXml(string saveFileName) {

//创建XmlSerializer对象,传入待反序列化数据的类型

var serializer = new XmlSerializer(typeof(T));

//创建FileStream对象,指定文件路径和操作模式。

string path = Path.Combine(Application.persistentDataPath, saveFileName);

var stream = new FileStream(path, FileMode.Create);

//从文件中反序列化数据,并转换为指定类型

var data = (T)serializer.Deserialize(stream);

stream.Close();

return data;

}

//删除

public static void DeleteSaveFile(string saveFileName) {

var path = Path.Combine(Application.persistentDataPath, saveFileName);

File.Delete(path);

}

}

调用类

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Test : MonoBehaviour {

//增加可序列化特性才能被转换

[System.Serializable]

class SaveData {

public string playerName;

public string playerLevel;

public string playerCoin;

public Vector3 playerPosition;

}

public string playerName;

public string playerLevel;

public string playerCoin;

public Vector3 playerPosition;

const string PLAYER_DATA_FILE_NAME = "PlayerData";

SaveData SavingData() {

var savaData = new SaveData();

savaData.playerName = playerName;

savaData.playerLevel = playerLevel;

savaData.playerCoin = playerCoin;

savaData.playerPosition = playerPosition;

return savaData;

}

//存档

void SaveByXML() {

SaveSystem.SaveByXml(PLAYER_DATA_FILE_NAME,SavingData());

}

//读档

void LoadFromJson() {

var saveData = SaveSystem.LoadFromXml(PLAYER_DATA_FILE_NAME);

LoadData(saveData);

}

void LoadData(SaveData saveData) {

playerName = saveData.playerName;

playerLevel = saveData.playerLevel;

playerCoin = saveData.playerCoin;

transform.position = saveData.playerPosition;

}

//删除

void DeletePlayerDataFiles() {

SaveSystem.DeleteSaveFile(PLAYER_DATA_FILE_NAME);

}

}

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: