当前位置: 首页 > news >正文

【Unity笔记04】数据持久化

🌟 方案核心思想

遵循以下设计原则:

  1. 数据安全第一:绝不使用明文存储,采用AES加密算法保护数据。
  2. 性能优化:使用异步I/O操作,避免阻塞主线程导致游戏卡顿。
  3. 结构清晰:模块化设计,职责分离,便于维护和扩展。
  4. 易于集成:提供单例入口,全局访问方便。

🧱 模块架构设计

整个数据持久化系统由四个核心模块组成:

PlayerData.cs

数据模型,定义可序列化的玩家数据结构

EncryptionUtility.cs

加密工具类,负责数据的加密与解密

AsyncFileUtility.cs

异步文件操作工具,封装读写逻辑

DataManager.cs

核心管理器,统一调度数据加载与保存

1️⃣ 玩家数据模型:PlayerData.cs

using System;
using System.Collections.Generic;
using UnityEngine;[Serializable]
public class PlayerData
{public string playerName;public int level;public long gold;public List<string> inventoryItems; // 背包物品列表public Dictionary<string, int> equippedGear; // 装备信息(部位 -> 物品ID)public int saveVersion; // 数据版本号,用于后续升级兼容// 构造函数,初始化默认值public PlayerData(string name, int lvl){playerName = name;level = lvl;gold = 0;inventoryItems = new List<string>();equippedGear = new Dictionary<string, int>();saveVersion = 1; // 初始版本}// 示例:添加物品public void AddItem(string item){inventoryItems.Add(item);}// 示例:升级public void LevelUp(){level++;Debug.Log($"玩家 {playerName} 升级到等级 {level}");}
}

2️⃣ 安全加密:EncryptionUtility.cs

切记:永远不要用明文存储数据!

我们采用 AES(Advanced Encryption Standard) 对称加密算法,结合CBC模式和PKCS7填充,确保数据安全。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;public static class EncryptionUtility
{// 🔐 演示用密钥(256位 = 32字节)private static readonly byte[] Key = Encoding.UTF8.GetBytes("YourVeryStrongAndSecretKey123456");// 🔐 演示用IV(128位 = 16字节)private static readonly byte[] IV = Encoding.UTF8.GetBytes("AnotherSecretIV1");/// <summary>/// 加密字符串/// </summary>public static string Encrypt(string plainText){if (string.IsNullOrEmpty(plainText)) return string.Empty;using (Aes aesAlg = Aes.Create()){aesAlg.Key = Key;aesAlg.IV = IV;aesAlg.Mode = CipherMode.CBC;aesAlg.Padding = PaddingMode.PKCS7;ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);using (MemoryStream msEncrypt = new MemoryStream()){using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)){using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)){swEncrypt.Write(plainText);}}byte[] encryptedBytes = msEncrypt.ToArray();return Convert.ToBase64String(encryptedBytes); // 转为Base64便于存储}}}/// <summary>/// 解密字符串/// </summary>public static string Decrypt(string cipherText){if (string.IsNullOrEmpty(cipherText)) return string.Empty;byte[] cipherBytes;try{cipherBytes = Convert.FromBase64String(cipherText);}catch (FormatException){Debug.LogError("解密失败:输入字符串不是有效的Base64格式。");return string.Empty;}using (Aes aesAlg = Aes.Create()){aesAlg.Key = Key;aesAlg.IV = IV;aesAlg.Mode = CipherMode.CBC;aesAlg.Padding = PaddingMode.PKCS7;ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);using (MemoryStream msDecrypt = new MemoryStream(cipherBytes)){using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)){using (StreamReader srDecrypt = new StreamReader(csDecrypt)){return srDecrypt.ReadToEnd();}}}}}
}

3️⃣ 异步文件操作:AsyncFileUtility.cs 

using UnityEngine;
using System.IO;
using System.Threading.Tasks;public static class AsyncFileUtility
{private static readonly string _saveDirectory = Application.persistentDataPath;/// <summary>/// 异步写入加密数据/// </summary>public static async Task WriteAllTextAsync(string encryptedData, string fileName){string filePath = Path.Combine(_saveDirectory, fileName);try{await File.WriteAllTextAsync(filePath, encryptedData);Debug.Log($"数据已成功异步写入到: {filePath}");}catch (System.Exception e){Debug.LogError($"异步写入文件失败({filePath}): {e.Message}");}}/// <summary>/// 异步读取加密数据/// </summary>public static async Task<string> ReadAllTextAsync(string fileName){string filePath = Path.Combine(_saveDirectory, fileName);if (!File.Exists(filePath)){Debug.LogWarning($"文件不存在: {filePath}");return null;}try{string encryptedData = await File.ReadAllTextAsync(filePath);Debug.Log($"数据已成功异步从: {filePath} 读取。");return encryptedData;}catch (System.Exception e){Debug.LogError($"异步读取文件失败({filePath}): {e.Message}");return null;}}
}

4️⃣ 核心管理器:DataManager.cs 

 

using UnityEngine;
using System;
using System.Threading.Tasks;public class DataManager : MonoBehaviour
{public static DataManager Instance { get; private set; }private PlayerData _currentPlayerData;private const string PLAYER_SAVE_FILE = "playerSave.json";// 数据加载完成事件,用于通知其他模块public static event Action<PlayerData> OnDataLoaded;void Awake(){if (Instance == null){Instance = this;DontDestroyOnLoad(gameObject); // 场景切换不销毁}else{Destroy(gameObject);}}void Start(){LoadGameAsync(); // 启动时自动加载}/// <summary>/// 异步加载游戏数据/// </summary>public async void LoadGameAsync(){Debug.Log("开始异步加载游戏数据...");string encryptedJson = await AsyncFileUtility.ReadAllTextAsync(PLAYER_SAVE_FILE);PlayerData loadedData = null;if (!string.IsNullOrEmpty(encryptedJson)){string jsonString = EncryptionUtility.Decrypt(encryptedJson);if (!string.IsNullOrEmpty(jsonString)){try{loadedData = JsonUtility.FromJson<PlayerData>(jsonString);// TODO: 可在此处添加版本兼容处理}catch (System.Exception e){Debug.LogError($"反序列化失败: {e.Message}");}}}_currentPlayerData = loadedData ?? new PlayerData("新玩家", 1);Debug.Log(loadedData != null ? "加载存档成功" : "创建新玩家");OnDataLoaded?.Invoke(_currentPlayerData);}/// <summary>/// 异步保存游戏数据/// </summary>public async void SaveGameAsync(){if (_currentPlayerData == null) return;Debug.Log("开始异步保存...");string jsonString = JsonUtility.ToJson(_currentPlayerData);string encryptedJson = EncryptionUtility.Encrypt(jsonString);await AsyncFileUtility.WriteAllTextAsync(encryptedJson, PLAYER_SAVE_FILE);Debug.Log("保存完成");}/// <summary>/// 获取当前玩家数据/// </summary>public PlayerData GetCurrentPlayerData() => _currentPlayerData;// 建议在暂停或后台时保存void OnApplicationPause(bool pauseStatus){if (pauseStatus) SaveGameAsync();}void OnApplicationQuit(){SaveGameAsync(); // 注意:异步可能无法保证完成}
}

在场景中创建一个空 GameObject(如命名为 DataManager),并挂载 DataManager.cs 脚本。 

 

http://www.lryc.cn/news/605893.html

相关文章:

  • TypeScript 基础介绍(二)
  • 雷霆战机游戏代码
  • ubuntu22.04系统入门 linux入门 简单命令基础复习 实现以及实践
  • Flask Bootstrap 后台权限管理方案
  • diffusion原理和代码延伸笔记1——扩散桥,GOUB,UniDB
  • 功能强大编辑器
  • PDF源码解析
  • QT Word模板 + QuaZIP + LibreOffice,跨平台方案实现导出.docx文件后再转为.pdf文件
  • WebSocket配置实战:打造稳健高效的消息通信系统
  • 学C笔记——更新于0731
  • 网络攻击新态势企业级安全防御指南
  • C# 枚举器和迭代器(常见迭代器模式)
  • 深入剖析:C++ 手写实现 unordered_map 与 unordered_set 全流程指南
  • 【React】fiber 架构
  • vue 中 props 直接解构的话会数据丢失响应式
  • MakeInstaller: 一款麒麟操作系统安装包制作工具
  • 3DXML 转换为 UG 的技术指南及迪威模型网在线转换推荐
  • DeepSeek笔记(三):结合Flask实现以WEB方式访问本地部署的DeepSeek-R1模型
  • 戴尔笔记本Ubuntu18.04 NVIDIA驱动与cuda环境配置教程
  • 【国内电子数据取证厂商龙信科技】内存取证
  • 工业绝缘监测仪:保障工业电气安全的关键防线
  • Towers
  • AI+金融,如何跨越大模型和场景鸿沟?
  • NXP i.MX8MP GPU 与核心库全景解析
  • mac操作笔记
  • C++ 入门基础(2)
  • MySQL自动化安装工具-mysqldeploy
  • 关于AR地产发展现状的深度探究​
  • 【AI大模型】披着羊皮的狼--自动化生成越狱提示的系统(ReNeLLM)
  • 无人机传感器系统架构解析