本章节部分讲述保存系统,需要使用教程提供的代码,关于保存系统代码部分,因为该部分略微复杂,教程并没有讲解过多的原理,我们暂时就当做一个API用来使用。
代码如下:
ISaveable:
- namespace RPG.Saving
- {
- public interface ISaveable
- {
- object CaptureState();
- void RestoreState(object state);
- }
- }
复制代码
SerializableVector3:
- using UnityEngine;
-
- namespace RPG.Saving
- {
- [System.Serializable]
- public class SerializableVector3
- {
- float x, y, z;
-
- public SerializableVector3(Vector3 vector)
- {
- x = vector.x;
- y = vector.y;
- z = vector.z;
- }
-
- public Vector3 ToVector()
- {
- return new Vector3(x, y, z);
- }
- }
- }
复制代码
SaveableEntity:
- using System;
- using System.Collections.Generic;
- using RPG.Core;
- using UnityEditor;
- using UnityEngine;
- using UnityEngine.AI;
-
- namespace RPG.Saving
- {
- [ExecuteAlways]
- public class SaveableEntity : MonoBehaviour
- {
- [SerializeField] string uniqueIdentifier = "";// 唯一标识符,用于区分不同的实体
- static Dictionary<string, SaveableEntity> globalLookup = new Dictionary<string, SaveableEntity>();
-
- // 获取该实体的唯一标识符
- public string GetUniqueIdentifier()
- {
- return uniqueIdentifier;
- }
- // 捕获该实体的状态
- public object CaptureState()
- {
- Dictionary<string, object> state = new Dictionary<string, object>();
- // 遍历所有实现了 ISaveable 接口的组件,捕获其状态
- foreach (ISaveable saveable in GetComponents<ISaveable>())
- {
- state[saveable.GetType().ToString()] = saveable.CaptureState();
- }
- return state;
- }
-
- // 恢复该实体的状态
- public void RestoreState(object state)
- {
- Dictionary<string, object> stateDict = (Dictionary<string, object>)state;
- // 遍历所有实现了 ISaveable 接口的组件,恢复其状态
- foreach (ISaveable saveable in GetComponents<ISaveable>())
- {
- string typeString = saveable.GetType().ToString();
- if (stateDict.ContainsKey(typeString))
- {
- saveable.RestoreState(stateDict[typeString]);
- }
- }
- }
-
- #if UNITY_EDITOR
- // 在编辑模式下更新唯一标识符
- private void Update()
- {
- if (Application.IsPlaying(gameObject)) return;// 如果游戏正在运行,则不执行此方法
- if (string.IsNullOrEmpty(gameObject.scene.path)) return;// 如果场景路径为空,则不执行此方法
-
- SerializedObject serializedObject = new SerializedObject(this);
- SerializedProperty property = serializedObject.FindProperty("uniqueIdentifier");
-
- // 如果唯一标识符为空或不唯一,则生成新的唯一标识符
- if (string.IsNullOrEmpty(property.stringValue) || !IsUnique(property.stringValue))
- {
- property.stringValue = System.Guid.NewGuid().ToString();
- serializedObject.ApplyModifiedProperties();
- }
-
- // 更新全局唯一标识符映射
- globalLookup[property.stringValue] = this;
- }
- #endif
- // 检查标识符是否唯一
- private bool IsUnique(string candidate)
- {
- // 如果全局映射中没有此标识符,则唯一
- if (!globalLookup.ContainsKey(candidate)) return true;
-
- // 如果映射中的实体是当前实体,则唯一
- if (globalLookup[candidate] == this) return true;
-
- // 如果映射中的实体为 null,则移除该映射并唯一
- if (globalLookup[candidate] == null)
- {
- globalLookup.Remove(candidate);
- return true;
- }
-
- // 如果映射中的实体的唯一标识符不匹配,则移除该映射并唯一
- if (globalLookup[candidate].GetUniqueIdentifier() != candidate)
- {
- globalLookup.Remove(candidate);
- return true;
- }
-
- return false;
- }
- }
- }
复制代码
SavingSystem:
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.Text;
- using UnityEngine;
- using UnityEngine.SceneManagement;
-
- namespace RPG.Saving
- {
- /// <summary>
- /// 保存和加载游戏状态的系统
- /// </summary>
- public class SavingSystem : MonoBehaviour
- {
- // 加载最后保存的场景,并恢复状态
- public IEnumerator LoadLastScene(string saveFile)
- {
- // 从文件中加载状态
- Dictionary<string, object> state = LoadFile(saveFile);
- // 获取当前活动场景的构建索引
- int buildIndex = SceneManager.GetActiveScene().buildIndex;
- // 如果保存的状态中包含了场景索引,则使用保存的索引
- if (state.ContainsKey("lastSceneBuildIndex"))
- {
- buildIndex = (int) state["lastSceneBuildIndex"];
- }
- // 异步加载场景
- yield return SceneManager.LoadSceneAsync(buildIndex);
- // 恢复场景状态
- RestoreState(state);
- }
-
- /// <summary>
- /// 保存当前状态到文件
- /// </summary>
- /// <param name="saveFile"></param>
- public void Save(string saveFile)
- {
- Dictionary<string, object> state = LoadFile(saveFile);
- CaptureState (state);
- SaveFile (saveFile, state);
- }
-
- /// <summary>
- /// 加载状态
- /// </summary>
- /// <param name="saveFile"></param>
- public void Load(string saveFile)
- {
- RestoreState(LoadFile(saveFile)); // 从文件中加载状态并恢复
- }
-
- /// <summary>
- /// 删除保存文件
- /// </summary>
- /// <param name="saveFile"></param>
- public void Delete(string saveFile)
- {
- File.Delete(GetPathFromSaveFile(saveFile));
- }
-
- /// <summary>
- /// 从文件中加载状态
- /// </summary>
- /// <param name="saveFile"></param>
- /// <returns></returns>
- private Dictionary<string, object> LoadFile(string saveFile)
- {
- // 获取文件路径
- string path = GetPathFromSaveFile(saveFile);
- // 如果文件不存在,返回一个空的状态字典
- if (!File.Exists(path))
- {
- return new Dictionary<string, object>();
- }
- // 打开文件流并反序列化状态字典
- using (FileStream stream = File.Open(path, FileMode.Open))
- {
- BinaryFormatter formatter = new BinaryFormatter();
- return (Dictionary<string, object>)
- formatter.Deserialize(stream);
- }
- }
- /// <summary>
- /// 将状态保存到文件
- /// </summary>
- /// <param name="saveFile"></param>
- /// <param name="state"></param>
- private void SaveFile(string saveFile, object state)
- {
- // 获取文件路径
- string path = GetPathFromSaveFile(saveFile);
- print("Saving to " + path);
- // 打开文件流并序列化状态字典
- using (FileStream stream = File.Open(path, FileMode.Create))
- {
- BinaryFormatter formatter = new BinaryFormatter();
- formatter.Serialize (stream, state);
- }
- }
- /// <summary>
- /// 捕获当前游戏对象的状态
- /// </summary>
- /// <param name="state"></param>
- private void CaptureState(Dictionary<string, object> state)
- {
- // 遍历所有可保存的实体
- foreach (SaveableEntity saveable in FindObjectsOfType<SaveableEntity>())
- {
- // 将实体的状态保存到字典中
- state[saveable.GetUniqueIdentifier()] = saveable.CaptureState();
- }
- // 将实体的状态保存到字典中
- state["lastSceneBuildIndex"] =
- SceneManager.GetActiveScene().buildIndex;
- }
- // 恢复游戏对象的状态
- private void RestoreState(Dictionary<string, object> state)
- {
- // 遍历所有可保存的实体
- foreach (SaveableEntity
- saveable
- in
- FindObjectsOfType<SaveableEntity>()
- )
- {
- // 获取实体的唯一标识符
- string id = saveable.GetUniqueIdentifier();
- // 如果状态字典中包含该标识符,则恢复状态
- if (state.ContainsKey(id))
- {
- saveable.RestoreState(state[id]);
- }
- }
- }
- // 获取保存文件的路径
- private string GetPathFromSaveFile(string saveFile)
- {
- // 将保存文件名和路径结合起来
- return Path
- .Combine(Application.persistentDataPath, saveFile + ".sav");
- }
- }
- }
复制代码
|