目录
一.整体思路
二.实现
1.用于实现写入与读取的类
因为要实现写入与读取,所以会涉及到c#的文件操作;
public class FileDataHandler
{
private string dataDirPath = "";
private string dataFileName = "";
public FileDataHandler(string _dataDirPath, string _dataFileName)
{
this.dataDirPath = _dataDirPath;
this.dataFileName = _dataFileName;
}
public void Save(GameData _data)
{
string fullPath = Path.Combine(dataDirPath, dataFileName);
try
{
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
string dataToStore = JsonUtility.ToJson(_data, true);
using (FileStream stream = new FileStream(fullPath, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(dataToStore);
}
}
}
catch (Exception e)
{
Debug.LogError("Error on trying to save data to file: " + fullPath + "\n" + e);
}
}
public GameData Load()
{
string fullPath = Path.Combine(dataDirPath, dataFileName);
GameData loadData = null;
if (File.Exists(fullPath))
{
try
{
string dataToLoad = "";
using (FileStream stream = new FileStream(fullPath, FileMode.Open))
{
using (StreamReader reader = new StreamReader(stream))
{
dataToLoad = reader.ReadToEnd();
}
}
loadData = JsonUtility.FromJson<GameData>(dataToLoad);
}
catch (Exception e)
{
Debug.Log("Fail to load " + fullPath + "\n" + e);
}
}
return loadData;
}
}
(0).写出来路径和文件名,确认存档位置。
Save:
(1)将路径与文件名字相连,并在对应位置创建存档文件;
(2)通过Unity中JsonUtility的ToJson方法将要存储的数据(_data)变为JSON格式;
(3)以Create模式打开对应位置的文件,并用StreamWriter对其进行写入;
Load:
(1)将路径与文件名字相连,确认对应位置有存档文件后以Open模式打开文件,并用StreamReader进行读取;
(2)将读取的数据用FromJson方法变为可加载的游戏数据,并用一个变量接收;
2.实现用于存储以及加载数据的接口
public interface ISaveManager
{
void LoadData(GameData _data);
void SaveData(ref GameData _data);
}
3.创建一个类,用于真正实现数据的交互
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class SaveManager : MonoBehaviour
{
public static SaveManager instance;
[SerializeField] private string fileName;
private GameData gameData;
private List<ISaveManager> saveManagers;
private FileDataHandler dataHandler;
private void Awake()
{
if (instance != null)
{
Destroy(instance.gameObject);
}
else
{
instance = this;
}
}
private void Start()
{
dataHandler = new FileDataHandler(Application.persistentDataPath, fileName);
saveManagers = FindAllSaveManager();
LoadData();
}
public void NewGame()
{
gameData = new GameData();
}
public void LoadData()
{
gameData = dataHandler.Load();
if (gameData == null)
{
Debug.Log("No saved data found");
NewGame();
}
foreach (ISaveManager saveManager in saveManagers)
{
saveManager.LoadData(gameData);
Debug.Log("Loaded");
}
}
public void SaveData()
{
foreach (ISaveManager saveManager in saveManagers)
{
///
Debug.Log("Data saved");
///
saveManager.SaveData(ref gameData);
}
dataHandler.Save(gameData);
}
private void OnApplicationQuit()
{
SaveData();
}
private List<ISaveManager> FindAllSaveManager()
{
IEnumerable<ISaveManager> saveManagers = FindObjectsOfType<MonoBehaviour>().OfType<ISaveManager>();
return new List<ISaveManager>(saveManagers);
}
}
Instance:
(0).做成单例模式是为了在各个需要存储数据地方都能够方便调用;
Start:
(1).用目标路径以及文件名声明一个FileDataHandler;
(2).用FindAllSavaManager方法找到所有使用了ISavaManager接口的脚本;最后执行LoadData
LoadData:
(1).首先获取存档,如果获取不到就新建一个,如果能获取到就对所有要加载数据的地方进行数据加载;
SaveData:
(1).在每个需要保存数据的地方进行数据保存,最后将修改好的gameData传入dataHandler中进行文件写入;
4.创建一个类,其中声明要存储的数据
//以下是我所学习的项目中需要保存的数据
using System.Collections.Generic;
[System.Serializable]
public class GameData
{
public int currency;
public SerializableDictionary<string, bool> skillTree;
public SerializableDictionary<string, int> inventory;
public List<string> equipmentID;
public SerializableDictionary<string, bool> checkPoints;
public string closestCheckPointID;
//位置
public float lostCurrencyX;
public float lostCurrencyY;
public int lostCurrencyAmount;
public SerializableDictionary<string, float> volumeSetting;
public GameData()
{
this.lostCurrencyX = 0;
this.lostCurrencyY = 0;
this.lostCurrencyAmount = 0;
this.currency = 0;
skillTree = new SerializableDictionary<string, bool>();
inventory = new SerializableDictionary<string, int>();
equipmentID = new List<string>();
checkPoints = new SerializableDictionary<string, bool>();
closestCheckPointID = string.Empty;
volumeSetting = new SerializableDictionary<string, float>();
}
}
(0).有需要保存的数据就声明并初始化即可,具体如何保存见下(只是举例,不必深究其中的变量等):
public void LoadData(GameData _data)
{
foreach (KeyValuePair<string, int> pair in _data.inventory)
{
foreach (var item in itemDataBase)
{
if (item != null && item.itemID == pair.Key)
{
InventoryItem itemToLoad = new InventoryItem(item);
itemToLoad.stackSize = pair.Value;
loadedItems.Add(itemToLoad);
}
}
}
foreach (string loadedItemID in _data.equipmentID)
{
foreach (var item in itemDataBase)
{
if (item != null && item.itemID == loadedItemID)
{
loadedEquipment.Add(item as ItemData_Equipment);
}
}
}
}
public void SaveData(ref GameData _data)
{
//清除,保存现在的数据
_data.inventory.Clear();
_data.equipmentID.Clear();
foreach (KeyValuePair<ItemData, InventoryItem> pair in inventoryDictionary)
{
_data.inventory.Add(pair.Key.itemID, pair.Value.stackSize);
}
foreach (KeyValuePair<ItemData, InventoryItem> pair in stashDictionary)
{
_data.inventory.Add(pair.Key.itemID, pair.Value.stackSize);
}
foreach (KeyValuePair<ItemData_Equipment, InventoryItem> pair in equipmentDictionary)
{
_data.equipmentID.Add(pair.Key.itemID);
}
}
SerializableDictionary:
(1).用SerializableDictionary是因为普通字典无法用该方法保存,SerializeableDictionary需 要自己创建
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField] private List<TKey> keys = new List<TKey>();
[SerializeField] private List<TValue> values = new List<TValue>();
public void OnBeforeSerialize()
{
keys.Clear();
values.Clear();
foreach (KeyValuePair<TKey, TValue> pair in this)
{
keys.Add(pair.Key);
values.Add(pair.Value);
}
}
public void OnAfterDeserialize()
{
this.Clear();
if (keys.Count != values.Count)
{
Debug.Log("Keys count not equal to values count");
}
for (int i = 0; i < keys.Count; i++)
{
this.Add(keys[i], values[i]);
}
}
}
三.补充
1.如何给物品分配ID
#if UNITY_EDITOR
string path = AssetDatabase.GetAssetPath(this);
itemID = AssetDatabase.AssetPathToGUID(path);
#endif
如有错误,还请指正
转载自CSDN-专业IT技术社区
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/2301_80342725/article/details/141612687