Unity学习笔记_简易的存档系统

目录

一.整体思路

二.实现

1.用于实现写入与读取的类

Save:

Load:

2.实现用于存储以及加载数据的接口

3.创建一个类,用于真正实现数据的交互

Instance:

Start:

LoadData:

SaveData:

4.创建要存储的数据类

SerializableDictionary:

三.补充

1.如何给物品分配ID


一.整体思路

        815dc851e1324f598dbf5a7eb0aeca56.png

 


二.实现

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

如有错误,还请指正

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值