Udemy-Unity制作类暗黑破坏神游戏记录-P77

2024-09-16
155看过
本章节部分讲述保存系统,需要使用教程提供的代码,关于保存系统代码部分,因为该部分略微复杂,教程并没有讲解过多的原理,我们暂时就当做一个API用来使用。

代码如下:
ISaveable:

  1. namespace RPG.Saving
  2. {
  3.     public interface ISaveable
  4.     {
  5.         object CaptureState();
  6.         void RestoreState(object state);
  7.     }
  8. }
复制代码
SerializableVector3:

  1. using UnityEngine;
  2. namespace RPG.Saving
  3. {
  4.     [System.Serializable]
  5.     public class SerializableVector3
  6.     {
  7.         float x, y, z;
  8.         public SerializableVector3(Vector3 vector)
  9.         {
  10.             x = vector.x;
  11.             y = vector.y;
  12.             z = vector.z;
  13.         }
  14.         public Vector3 ToVector()
  15.         {
  16.             return new Vector3(x, y, z);
  17.         }
  18.     }
  19. }
复制代码
SaveableEntity:

  1. using System;
  2. using System.Collections.Generic;
  3. using RPG.Core;
  4. using UnityEditor;
  5. using UnityEngine;
  6. using UnityEngine.AI;
  7. namespace RPG.Saving
  8. {
  9.     [ExecuteAlways]
  10.     public class SaveableEntity : MonoBehaviour
  11.     {
  12.         [SerializeField] string uniqueIdentifier = "";// 唯一标识符,用于区分不同的实体
  13.         static Dictionary<string, SaveableEntity> globalLookup = new Dictionary<string, SaveableEntity>();
  14.         // 获取该实体的唯一标识符
  15.         public string GetUniqueIdentifier()
  16.         {
  17.             return uniqueIdentifier;
  18.         }
  19.         // 捕获该实体的状态
  20.         public object CaptureState()
  21.         {
  22.             Dictionary<string, object> state = new Dictionary<string, object>();
  23.             // 遍历所有实现了 ISaveable 接口的组件,捕获其状态
  24.             foreach (ISaveable saveable in GetComponents<ISaveable>())
  25.             {
  26.                 state[saveable.GetType().ToString()] = saveable.CaptureState();
  27.             }
  28.             return state;
  29.         }
  30.         // 恢复该实体的状态
  31.         public void RestoreState(object state)
  32.         {
  33.             Dictionary<string, object> stateDict = (Dictionary<string, object>)state;
  34.             // 遍历所有实现了 ISaveable 接口的组件,恢复其状态
  35.             foreach (ISaveable saveable in GetComponents<ISaveable>())
  36.             {
  37.                 string typeString = saveable.GetType().ToString();
  38.                 if (stateDict.ContainsKey(typeString))
  39.                 {
  40.                     saveable.RestoreState(stateDict[typeString]);
  41.                 }
  42.             }
  43.         }
  44. #if UNITY_EDITOR
  45.         // 在编辑模式下更新唯一标识符
  46.         private void Update()
  47.         {
  48.             if (Application.IsPlaying(gameObject)) return;// 如果游戏正在运行,则不执行此方法
  49.             if (string.IsNullOrEmpty(gameObject.scene.path)) return;// 如果场景路径为空,则不执行此方法
  50.             SerializedObject serializedObject = new SerializedObject(this);
  51.             SerializedProperty property = serializedObject.FindProperty("uniqueIdentifier");
  52.             // 如果唯一标识符为空或不唯一,则生成新的唯一标识符
  53.             if (string.IsNullOrEmpty(property.stringValue) || !IsUnique(property.stringValue))
  54.             {
  55.                 property.stringValue = System.Guid.NewGuid().ToString();
  56.                 serializedObject.ApplyModifiedProperties();
  57.             }
  58.             // 更新全局唯一标识符映射
  59.             globalLookup[property.stringValue] = this;
  60.         }
  61. #endif
  62.         // 检查标识符是否唯一
  63.         private bool IsUnique(string candidate)
  64.         {
  65.             // 如果全局映射中没有此标识符,则唯一
  66.             if (!globalLookup.ContainsKey(candidate)) return true;
  67.             // 如果映射中的实体是当前实体,则唯一
  68.             if (globalLookup[candidate] == this) return true;
  69.             // 如果映射中的实体为 null,则移除该映射并唯一
  70.             if (globalLookup[candidate] == null)
  71.             {
  72.                 globalLookup.Remove(candidate);
  73.                 return true;
  74.             }
  75.             // 如果映射中的实体的唯一标识符不匹配,则移除该映射并唯一
  76.             if (globalLookup[candidate].GetUniqueIdentifier() != candidate)
  77.             {
  78.                 globalLookup.Remove(candidate);
  79.                 return true;
  80.             }
  81.             return false;
  82.         }
  83.     }
  84. }
复制代码
SavingSystem:

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Runtime.Serialization.Formatters.Binary;
  6. using System.Text;
  7. using UnityEngine;
  8. using UnityEngine.SceneManagement;
  9. namespace RPG.Saving
  10. {
  11.     /// <summary>
  12.     /// 保存和加载游戏状态的系统
  13.     /// </summary>
  14.     public class SavingSystem : MonoBehaviour
  15.     {
  16.         // 加载最后保存的场景,并恢复状态
  17.         public IEnumerator LoadLastScene(string saveFile)
  18.         {
  19.             // 从文件中加载状态
  20.             Dictionary<string, object> state = LoadFile(saveFile);
  21.             // 获取当前活动场景的构建索引
  22.             int buildIndex = SceneManager.GetActiveScene().buildIndex;
  23.             // 如果保存的状态中包含了场景索引,则使用保存的索引
  24.             if (state.ContainsKey("lastSceneBuildIndex"))
  25.             {
  26.                 buildIndex = (int) state["lastSceneBuildIndex"];
  27.             }
  28.             // 异步加载场景
  29.             yield return SceneManager.LoadSceneAsync(buildIndex);
  30.             // 恢复场景状态
  31.             RestoreState(state);
  32.         }
  33.         /// <summary>
  34.         /// 保存当前状态到文件
  35.         /// </summary>
  36.         /// <param name="saveFile"></param>
  37.         public void Save(string saveFile)
  38.         {
  39.             Dictionary<string, object> state = LoadFile(saveFile);
  40.             CaptureState (state);
  41.             SaveFile (saveFile, state);
  42.         }
  43.         /// <summary>
  44.         /// 加载状态
  45.         /// </summary>
  46.         /// <param name="saveFile"></param>
  47.         public void Load(string saveFile)
  48.         {
  49.             RestoreState(LoadFile(saveFile)); // 从文件中加载状态并恢复
  50.         }
  51.         /// <summary>
  52.         /// 删除保存文件
  53.         /// </summary>
  54.         /// <param name="saveFile"></param>
  55.         public void Delete(string saveFile)
  56.         {
  57.             File.Delete(GetPathFromSaveFile(saveFile));
  58.         }
  59.         /// <summary>
  60.         /// 从文件中加载状态
  61.         /// </summary>
  62.         /// <param name="saveFile"></param>
  63.         /// <returns></returns>
  64.         private Dictionary<string, object> LoadFile(string saveFile)
  65.         {
  66.             // 获取文件路径
  67.             string path = GetPathFromSaveFile(saveFile);
  68.             // 如果文件不存在,返回一个空的状态字典
  69.             if (!File.Exists(path))
  70.             {
  71.                 return new Dictionary<string, object>();
  72.             }
  73.             // 打开文件流并反序列化状态字典
  74.             using (FileStream stream = File.Open(path, FileMode.Open))
  75.             {
  76.                 BinaryFormatter formatter = new BinaryFormatter();
  77.                 return (Dictionary<string, object>)
  78.                 formatter.Deserialize(stream);
  79.             }
  80.         }
  81.         /// <summary>
  82.         /// 将状态保存到文件
  83.         /// </summary>
  84.         /// <param name="saveFile"></param>
  85.         /// <param name="state"></param>
  86.         private void SaveFile(string saveFile, object state)
  87.         {
  88.             // 获取文件路径
  89.             string path = GetPathFromSaveFile(saveFile);
  90.             print("Saving to " + path);
  91.             // 打开文件流并序列化状态字典
  92.             using (FileStream stream = File.Open(path, FileMode.Create))
  93.             {
  94.                 BinaryFormatter formatter = new BinaryFormatter();
  95.                 formatter.Serialize (stream, state);
  96.             }
  97.         }
  98.         /// <summary>
  99.         ///  捕获当前游戏对象的状态
  100.         /// </summary>
  101.         /// <param name="state"></param>
  102.         private void CaptureState(Dictionary<string, object> state)
  103.         {
  104.             // 遍历所有可保存的实体
  105.             foreach (SaveableEntity saveable in FindObjectsOfType<SaveableEntity>())
  106.             {
  107.                 // 将实体的状态保存到字典中
  108.                 state[saveable.GetUniqueIdentifier()] = saveable.CaptureState();
  109.             }
  110.             // 将实体的状态保存到字典中
  111.             state["lastSceneBuildIndex"] =
  112.                 SceneManager.GetActiveScene().buildIndex;
  113.         }
  114.         // 恢复游戏对象的状态
  115.         private void RestoreState(Dictionary<string, object> state)
  116.         {
  117.             // 遍历所有可保存的实体
  118.             foreach (SaveableEntity
  119.                 saveable
  120.                 in
  121.                 FindObjectsOfType<SaveableEntity>()
  122.             )
  123.             {
  124.                 // 获取实体的唯一标识符
  125.                 string id = saveable.GetUniqueIdentifier();
  126.                 // 如果状态字典中包含该标识符,则恢复状态
  127.                 if (state.ContainsKey(id))
  128.                 {
  129.                     saveable.RestoreState(state[id]);
  130.                 }
  131.             }
  132.         }
  133.         // 获取保存文件的路径
  134.         private string GetPathFromSaveFile(string saveFile)
  135.         {
  136.             // 将保存文件名和路径结合起来
  137.             return Path
  138.                 .Combine(Application.persistentDataPath, saveFile + ".sav");
  139.         }
  140.     }
  141. }
复制代码



回复

举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表