保存常用数据类型,可以在 inspector 窗口中查看,例如
把怪物、玩家的属性保存成 ScriptableObject
《麦田物语》系列中,把物品数据保存成 ScriptableObject 类似下面的做法
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu(fileName = "CropData", menuName = "CropData/CropData", order = 0)]
public class CropDataList_SO : ScriptableObject
{
///
/// 农作物数据库
///
public List<CropDetails> cropDetailsList;
}
然后就可以在 project 窗口中,右键创建 ItemData
填写数据并使用 public ItemData itemDataList;
下面是 3DRPG 基础系列中《SaveManager.cs》保存玩家数据的例子
保存键值对,但可以配合 JsonUtility 来保存对象
private void Save(Object data, string key)
{
var jsonData = JsonUtility.ToJson(data);
PlayerPrefs.SetString(key, jsonData);
PlayerPrefs.SetString(sceneName, SceneManager.GetActiveScene().name);
PlayerPrefs.Save();
}
private void Load(Object data, string key)
{
if (PlayerPrefs.HasKey(key))
{
JsonUtility.FromJsonOverwrite(PlayerPrefs.GetString(key), data);
}
}
再封装一层使用
public void LoadPlayerData()
{
var data = GameManager.Instance.playerStats.characterData;
Load(data, data.name);
}
public void SavePlayerData()
{
var data = GameManager.Instance.playerStats.characterData;
Save(data, data.name);
}
不同的操作系统有不同的保存路径
使用官方的 JSON 包 Newtonsoft Json
下面的例子是《麦田物语》中,使用 3 个存档条保存数据
使用接口为需要存档功能的不同物体(GUID)拓展存档功能
public interface ISaveable
{
string GUID { get; }
GameSaveData GenerateSaveData();
void RestoreSaveData(GameSaveData saveData);
// 自 C Sharp 9.0 版本后,可以在接口中实现方法
// 在该接口写一个注册方法
void RegisterSaveable()
{
SaveLoadManager.Instance.RegisterSaveable(this);
}
}
获取GUID
using UnityEngine;
[ExecuteAlways]
public class DataGUID : MonoBehaviour
{
// 挂载在需要存储的物体上,实现存储数据的唯一性
public string guid;
private void Awake() {
if (guid==string.Empty)
{
// 16 位长度的字符串
guid = System.Guid.NewGuid().ToString();
}
}
}
读写数据
private void Save(int index)
{
// 保存到哪一条存档位置里
DataSlot data = new DataSlot();
foreach (var saveable in saveableList)
{
data.dataSlotDict.Add(saveable.GUID, saveable.GenerateSaveData());
}
dataSlotList[index] = data;
// 序列化后写入文件中存储
// 最终路径
var resultPath = jsonFolder + "data" + index + ".sav";
// 带缩进格式去存储 序列化数据
var jsonData = JsonConvert.SerializeObject(dataSlotList[index], Formatting.Indented);
if (!File.Exists(resultPath))
{
Directory.CreateDirectory(jsonFolder);
}
// 写入文件
File.WriteAllText(resultPath, jsonData);
}
读取数据
public void Load(int index)
{
currentDataIndex = index;
var resultPath = jsonFolder + "data" + index + ".sav";
if (File.Exists(resultPath))
{
var stringData = File.ReadAllText(resultPath);
// 反序列化
var jsonData = JsonConvert.DeserializeObject<DataSlot>(stringData);
foreach (var saveable in saveableList)
{
saveable.RestoreSaveData(jsonData.dataSlotDict[saveable.GUID]);
}
}
else
{
Debug.LogError("存档文件丢失");
}
}
使用接口时,先注册一下,再实现对应的方法即可
public class TransitionManager : Singleton
void Start()
{
ISaveable saveable = this;
saveable.RegisterSaveable();
fadeCanvasGroup = FindObjectOfType<CanvasGroup>();
}
public GameSaveData GenerateSaveData()
{
GameSaveData saveData = new GameSaveData();
saveData.dataSceneName = sceneName;
return saveData;
}
public void RestoreSaveData(GameSaveData saveData)
{
// Debug.Log("重新加载场景");
sceneName = saveData.dataSceneName;
// 按照游戏存档,重新加载场景内容
StartCoroutine(LoadSaveDataScene(sceneName));
}