Unity之Serialized序列化:从原理到实践

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity之Serialized序列化:从原理到实践
     
TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索
TechX —— 心探索、心进取!

助力快速掌握 Serialized序列化 学习

为初学者节省宝贵的学习时间,避免困惑!


文章目录

  • 一、 引言
  • 二、什么是序列化?
  • 三、Unity游戏对象的序列化
  • 四、脚本变量的序列化
    • 1、 [SerializeField]:私有字段的序列化
    • 2、 [System.Serializable]:自定义类的序列化
  • 五、ScriptableObject序列化
  • 六、常见序列化格式
    • 1、 JSON序列化(Newtonsoft.Json)
    • 2、CSV序列化(CsvHelper库)
    • 3、Excel序列化 (EPPlus库)
    • 4、XML序列化


一、 引言


在Unity开发中,序列化(Serialization) 是贯穿整个开发流程的核心技术。无论是游戏对象的持久化存储、Inspector面板的变量显示,还是跨平台数据交换,都离不开序列化的支持。对于编辑器扩展开发而言,深入理解序列化机制更是实现自定义工具和高效数据管理的关键。

为什么需要关注序列化?

  • 数据持久化:保存玩家存档、配置数据、场景状态。

  • Inspector交互:在编辑器中直观调整脚本参数。

  • 跨平台兼容:通过标准格式(如JSON)实现不同平台间的数据交换。

  • 性能优化:合理的序列化策略可减少内存占用和加载时间。



二、什么是序列化?


序列化是将对象转换为可存储或传输的格式(如二进制、JSON等)的过程,使得数据能在不同系统或平台间共享。反向的反序列化则是将这些格式数据还原为原始对象的过程。

在Unity中,序列化的典型场景包括:

  • 场景文件:将游戏对象层次结构和组件数据保存为.unity文件
  • Prefab:保存预设对象的模板
  • Inspector面板:显示并修改脚本的序列化字段
  • 数据持久化:存档、配置文件或网络通信


三、Unity游戏对象的序列化


游戏对象与组件的自动序列化
Unity的GameObject和Component(如Transform、Renderer等)默认支持序列化。其数据保存在场景或Prefab文件中,包括层级关系、组件属性等。

场景文件示例
打开一个.unity场景文件,可以看到类似以下结构的序列化数据:

--- !u!1 &12345
GameObject:m_Name: Playerm_Component:- component: {fileID: 123456}
--- !u!4 &123456
Transform:m_LocalPosition: {x: 0, y: 0, z: 0}m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}

序列化的限制
并非所有类型都能被Unity自动序列化。以下情况会导致字段不被序列化:

  • 静态字段(static)
  • 非继承自UnityEngine.Object的类引用
  • 标记为[NonSerialized]的字段
  • 属性(Properties):仅支持字段序列化。
  • 未标记的私有字段:需使用[SerializeField]。
  • 某些引用类型:如Dictionary(需自定义序列化)。


四、脚本变量的序列化


通过特性标记,开发者可以控制脚本中哪些字段需要序列化并在Inspector中显示。

1、 [SerializeField]:私有字段的序列化


Unity默认只会序列化public字段。若需序列化私有或受保护字段,可使用[SerializeField]。

public class Player : MonoBehaviour {[SerializeField]private int health = 100;  // Inspector中可见
}

2、 [System.Serializable]:自定义类的序列化


自定义类或结构体需添加[System.Serializable]属性,才能在Inspector中显示或被Unity序列化。

[System.Serializable]
public class Weapon {public string name;public int damage;
}public class Inventory : MonoBehaviour {public List<Weapon> weapons;  // 列表中每个Weapon属性都可在Inspector编辑
}

最佳实践
避免过度序列化:仅序列化必要数据以减少内存开销
版本兼容性:修改序列化类时注意向后兼容性(如添加新字段不影响旧数据)



五、ScriptableObject序列化


ScriptableObject是Unity提供的一个功能强大的工具,通常用于保存游戏数据、配置数据等。ScriptableObject在Unity中是非常重要的,它不仅能够序列化数据,还能够让你避免创建多个实例化的对象。

ScriptableObject核心特性:

  • 独立数据容器:不与场景绑定,保存于.asset文件
  • 运行时修改持久化:编辑器模式下修改可保存到项目
  • 高效引用系统:作为资产被多个对象引用
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif[System.Serializable]
public class SkillEffect {public enum EffectType { Damage, Heal, Buff }public EffectType type;public float value;public float duration;
}[System.Serializable]
public class SkillLevel {[Range(1, 100)]public int requiredLevel = 1;public float manaCost;public SkillEffect[] effects;
}// 主ScriptableObject类
[CreateAssetMenu(fileName = "New Skill", menuName = "RPG/Skill Config")]
public class SkillConfig : ScriptableObject {public string skillName;public Sprite icon;public float baseCooldown;[TextArea(3, 5)]public string description;[Space]public SkillLevel[] levels = new SkillLevel[5]; // 最多5级技能
}public class SkillSystemTest : MonoBehaviour {void Start() {// 创建临时技能配置SkillConfig tempSkill = CreateSkill("雷电术", new SkillLevel {requiredLevel = 5,manaCost = 30,effects = new[] {new SkillEffect {type = SkillEffect.EffectType.Damage,value = 50,duration = 2}}});// 在编辑器模式下保存资产#if UNITY_EDITORAssetDatabase.CreateAsset(tempSkill, "Assets/Skills/Lightning.asset");AssetDatabase.SaveAssets();#endif}SkillConfig CreateSkill(string name, params SkillLevel[] levels) {SkillConfig config = ScriptableObject.CreateInstance<SkillConfig>();config.skillName = name;config.levels = levels;return config;}
}


六、常见序列化格式


1、 JSON序列化(Newtonsoft.Json)


为什么选择Newtonsoft?

  • 原生JsonUtility不足:不支持字典、私有字段嵌套类
  • Newtonsoft特性:高效灵活,支持复杂类型转换
  • 安装方法:通过Unity Package Manager添加com.unity.nuget.newtonsoft-json
using Newtonsoft.Json;
using System.Collections.Generic;
using UnityEngine;// 复杂数据结构示例(包含嵌套类和字典)
[System.Serializable]
public class Player {public string name;[SerializeField]private int _health; //私有字段支持序列化public Dictionary<string, int> skills = new Dictionary<string, int>();// 自定义Vector3序列化(需转换) [JsonIgnore]public Vector3 position;[JsonProperty("position")]private Vector3Serializable PositionSerializable {get => new Vector3Serializable(position);set => position = value.ToVector3();}
}// Vector3序列化辅助类
[System.Serializable]
public struct Vector3Serializable {public float x;public float y;public float z;public Vector3Serializable(Vector3 v) {x = v.x;y = v.y;z = v.z;}public Vector3 ToVector3() => new Vector3(x, y, z);
}public class JsonExample : MonoBehaviour {void Start() {Player player = new Player {name = "Arthur",_health = 200,position = new Vector3(10, 2, 5)};player.skills.Add("Attack", 85);player.skills.Add("Defense", 60);// 序列化string json = JsonConvert.SerializeObject(player, Formatting.Indented);Debug.Log("JSON Output:\n" + json);// 反序列化Player loadedPlayer = JsonConvert.DeserializeObject<Player>(json);Debug.Log($"Position: {loadedPlayer.position}");}
}

控制台输出:

{"name": "Arthur","skills": {"Attack": 85,"Defense": 60},"position": {"x": 10.0,"y": 2.0,"z": 5.0}
}

关键注释:

  • [JsonIgnore]:标记不参与序列化的字段
  • [JsonProperty]:自定义字段映射名称
  • Vector3Serializable:需要手动处理Unity引擎特有类型

2、CSV序列化(CsvHelper库)


CsvHelper核心功能

  • 自动映射类属性到CSV列
  • 处理标题行复杂数据类型
  • 安装方法:通过NuGet安装CsvHelper
using CsvHelper;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityEngine;// CSV数据模型类
public class EnemyData {public int Id { get; set; }public string Name { get; set; }public float Speed { get; set; }public string PrefabPath { get; set; }
}public class CsvExample : MonoBehaviour {private string csvPath = "Enemies.csv";void Start() {WriteCSV();ReadCSV();}//序列化 将数据写入CSV文件中void WriteCSV() {List<EnemyData> enemies = new List<EnemyData> {new EnemyData { Id = 1, Name = "Goblin", Speed = 3.5f, PrefabPath = "Prefabs/Enemies/Goblin" },new EnemyData { Id = 2, Name = "Dragon", Speed = 8.0f, PrefabPath = "Prefabs/Enemies/Dragon" }};using (var writer = new StreamWriter(csvPath))using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) {csv.WriteRecords(enemies);}Debug.Log("CSV写入完成!");}//反序列化 将读取到的数据转换成类void ReadCSV() {using (var reader = new StreamReader(csvPath))using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) {var records = csv.GetRecords<EnemyData>();foreach (var enemy in records) {Debug.Log($"ID: {enemy.Id}, Name: {enemy.Name}, Speed: {enemy.Speed}");}}}
}

生成CSV内容:

Id,Name,Speed,PrefabPath
1,Goblin,3.5,Prefabs/Enemies/Goblin
2,Dragon,8,Prefabs/Enemies/Dragon

3、Excel序列化 (EPPlus库)


EPPlus库核心能力

  • 创建、修改.xlsx文件
  • 支持公式、样式、图表
  • 安装:从NuGet安装EPPlus(注意Unity需使用兼容版本)
using OfficeOpenXml;
using System;
using System.IO;
using UnityEngine;public class ExcelExample : MonoBehaviour {private string excelPath = "GameData.xlsx";void Start() {WriteExcel();ReadExcel();}private void WriteExcel() {ExcelPackage.LicenseContext = LicenseContext.NonCommercial;// 序列化 写入数据 创建新Excel文件using (ExcelPackage package = new ExcelPackage()) {// 添加工作表ExcelWorksheet sheet = package.Workbook.Worksheets.Add("玩家数据");// 填充标题行sheet.Cells[1, 1].Value = "ID";sheet.Cells[1, 2].Value = "Name";sheet.Cells[1, 3].Value = "Level";sheet.Cells[1, 4].Value = "LastLogin";// 填充数据sheet.Cells[2, 1].Value = 101;sheet.Cells[2, 2].Value = "Player1";sheet.Cells[2, 3].Value = 15;sheet.Cells[2, 4].Value = DateTime.Now;// 保存文件FileStream fileStream = new FileStream(excelPath, FileMode.Create);package.SaveAs(fileStream);fileStream.Close();}Debug.Log("Excel写入完成!");}//反序列化 读取数据private void ReadExcel() {using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) {ExcelWorksheet sheet = package.Workbook.Worksheets["玩家数据"];int rowCount = sheet.Dimension.Rows;for (int row = 2; row <= rowCount; row++) { //跳过标题行int id = int.Parse(sheet.Cells[row, 1].Text);string name = sheet.Cells[row, 2].Text;int level = int.Parse(sheet.Cells[row,3].Text);DateTime lastLogin = DateTime.Parse(sheet.Cells[row,4].Text);Debug.Log($"读取到玩家:{name} (等级{level}), 最后登录时间:{lastLogin}");}}}
}

4、XML序列化


核心优势:

  • 严格的树状数据格式,支持复杂嵌套结构
  • 内置Schema验证(XSD)保证数据完整性
  • 支持注释和CDATA块处理特殊字符
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using UnityEngine;// 装备品类(嵌套定义)
[System.Serializable]
public class EquipmentItem {public enum ItemRarity { Common, Rare, Epic }[XmlAttribute("id")]  // 设置为XML属性public string itemID;[XmlElement("displayName")] // 设置为XML元素public string itemName;[XmlIgnore]  // 不参与XML序列化public ItemRarity rarity;[XmlElement("durability")]public int currentDurability = 100;// 自定义字段序列化转换器[XmlElement("rarity")]public string RarityString {get => rarity.ToString();set => rarity = (ItemRarity)System.Enum.Parse(typeof(ItemRarity), value);}
}// 角色装备数据容器
[System.Serializable]
public class CharacterEquipment {[XmlArray("WeaponSlots")] // 定义数组包裹元素[XmlArrayItem("Weapon")]public List<EquipmentItem> weapons = new List<EquipmentItem>();[XmlArray("ArmorSlots")][XmlArrayItem("Armor")]public EquipmentItem[] armors = new EquipmentItem[4]; // 固定长度数组
}public class XMLSerializeExample : MonoBehaviour {private string xmlPath = "CharacterData.xml";void Start() {// 创建测试数据CharacterEquipment equipment = new CharacterEquipment {weapons = {new EquipmentItem { itemID = "w_001", itemName = "Steel Sword", rarity = EquipmentItem.ItemRarity.Epic },new EquipmentItem { itemID = "w_002", itemName = "Wooden Bow", rarity = EquipmentItem.ItemRarity.Common }},armors = {new EquipmentItem { itemID = "a_001", itemName = "Iron Helmet" },null, // 演示空元素处理方法new EquipmentItem { itemID = "a_003", itemName = "Chainmail" }}};// 序列化到文件SerializeToXML(equipment, xmlPath);// 从文件反序列化CharacterEquipment loadedData = DeserializeFromXML<CharacterEquipment>(xmlPath);Debug.Log($"加载的武器数量: {loadedData.weapons.Count}");}void SerializeToXML<T>(T data, string path) {XmlSerializer serializer = new XmlSerializer(typeof(T));using (StreamWriter stream = new StreamWriter(path)) {serializer.Serialize(stream, data);}Debug.Log($"XML序列化完成,文件尺寸:{new FileInfo(path).Length} bytes");}T DeserializeFromXML<T>(string path) {XmlSerializer serializer = new XmlSerializer(typeof(T));using (StreamReader stream = new StreamReader(path)) {return (T)serializer.Deserialize(stream);}}
}

XML输出结构:

<CharacterEquipment><WeaponSlots><Weapon id="w_001"><displayName>Steel Sword</displayName><rarity>Epic</rarity><durability>100</durability></Weapon><Weapon id="w_002"><displayName>Wooden Bow</displayName><rarity>Common</rarity><durability>100</durability></Weapon></WeaponSlots><ArmorSlots><Armor id="a_001"><displayName>Iron Helmet</displayName><rarity>Common</rarity><durability>100</durability></Armor><Armor /><Armor id="a_003"><displayName>Chainmail</displayName><rarity>Common</rarity><durability>100</durability></Armor></ArmorSlots>
</CharacterEquipment>

关键注解:

  • [XmlAttribute]:将字段序列化为XML属性(紧凑格式)
  • [XmlElement]:自定义元素名称(默认使用字段名)
  • [XmlArray]+[XmlArrayItem]:控制集合的嵌套结构
  • 自定义属性转换器:处理枚举类型与字符串的转换




TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步


END
感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/22119.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈模组-相机鬼像

一&#xff0e;前言 在成像中&#xff0c;我们常常会遇到肉眼观测的真实世界中&#xff0c;不存在的异常光影出现在画面中&#xff0c;并伴有各种颜色&#xff0c;我们将这个物体称为鬼像。某些鬼像可能会对图像产生美感的体验&#xff0c;但是大多数的鬼像都会对图像的质量以…

Python爬虫实战:爬取豆瓣电影

目录 引言 1. 爬虫基础 1.1 什么是爬虫&#xff1f; 1.2 Python爬虫常用库 2. 实战&#xff1a;抓取豆瓣电影Top250 2.1 安装依赖库 2.2 发送HTTP请求 ​编辑 2.3 解析HTML ​编辑 2.4 存储数据 2.5 完整代码 3. 进阶&#xff1a;处理分页和动态内容 3.1 抓取多页…

Redis7——基础篇(六)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…

Windows 下 Ollama 安装deepseek本地模型

Windows 下 Ollama 安装deepseek本地模型 安装 Ollama 下载 Ollama 下载链接&#xff1a;https://ollama.org.cn/download/windows 下载完成后&#xff0c;按照提示进行安装。 安装过程 安装完成后&#xff0c;安装页面会自动关闭&#xff0c;这是正常现象。 接下来&#…

【鸿蒙开发】第四十三章 Notification Kit(用户通知服务)

目录​​​​​​​ 1 简介 1.1 使用场景 1.2 能力范围 1.3 业务流程 1.4 通知样式 1.5 约束限制 1.6 与相关Kit的关系 2 请求通知授权 2.1 接口说明 2.2 开发步骤 3 管理通知角标 3.1 接口说明 3.2 开发步骤 4 管理通知渠道 4.1 通知渠道类型说明 4.2 接口说明…

bboss v7.3.5来袭!新增异地灾备机制和Kerberos认证机制,助力企业数据安全

ETL & 流批一体化框架 bboss v7.3.5 发布&#xff0c;多源输出插件增加为特定输出插件设置记录过滤功能&#xff1b;Elasticsearch 客户端新增异地双中心灾备机制&#xff0c;提升框架高可用性&#xff1b;Elasticsearch client 和 http 微服务框架增加对 Kerberos 认证支持…

利用非球面透镜进行激光光束重组

这是高斯分布激光束重塑透镜设计的分步演示。该透镜用于将高斯分布转换为成像平面上的均匀照明。 输入激光光束轮廓&#xff1a; 光学结构&#xff1a; Excel 中坐标的数学计算&#xff1a; 输出照度曲线&#xff1a;

(一)趣学设计模式 之 单例模式!

目录 一、啥是单例模式&#xff1f;二、为什么要用单例模式&#xff1f;三、单例模式怎么实现&#xff1f;1. 饿汉式&#xff1a;先下手为强&#xff01; &#x1f608;2. 懒汉式&#xff1a;用的时候再创建&#xff01; &#x1f634;3. 枚举&#xff1a;最简单最安全的单例&a…

nacos编写瀚高数据库插件

1、下载nacos源码 git clone gitgithub.com:alibaba/nacos.git 2、引入瀚高驱动 <dependency><groupId>com.highgo</groupId><artifactId>jdbc</artifactId><version>${highgo.version}</version></dependency> 3、DataSource…

讯飞唤醒+VOSK语音识别+DEEPSEEK大模型+讯飞离线合成实现纯离线大模型智能语音问答。

在信息爆炸的时代&#xff0c;智能语音问答系统正以前所未有的速度融入我们的日常生活。然而&#xff0c;随着数据泄露事件的频发&#xff0c;用户对于隐私保护的需求日益增强。想象一下&#xff0c;一个无需联网、即可响应你所有问题的智能助手——这就是纯离线大模型智能语音…

后端Java Stream数据流的使用=>代替for循环

API讲解 对比 示例代码对比 for循环遍历 package cn.ryanfan.platformback.service.impl;import cn.ryanfan.platformback.entity.Algorithm; import cn.ryanfan.platformback.entity.AlgorithmCategory; import cn.ryanfan.platformback.entity.DTO.AlgorithmInfoDTO; im…

UE 播放视频

一.UI播放视频 1.导入视频文件至工程文件夹 2.文件夹内右健选择Media -> File Meida Source创建testFileMeidaSource文件。 编辑FilePath为当前视频 3.右键->Media->Media Player 创建testMediaPlayer文件 4.右键创建testMediaTexture。编辑MediaPlayer设置testMedia…

推荐一款AI大模型托管平台-OpenWebUI

推荐一款AI大模型托管平台-OpenWebUI 1. OpenWebUI 1. OpenWebUI什么? 官网地址&#xff1a;https://openwebui.com/ GitHub地址&#xff1a; https://github.com/open-webui/open-webui Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台&#xff0c;旨在完全离…

【Python项目】基于知识图谱的百科问答系统

【Python项目】基于知识图谱的百科问答系统 技术简介&#xff1a; 采用Python技术、MySQL数据库、Django框架、Scrapy爬虫等技术实现。 系统简介&#xff1a; 百科问答系统是一个基于知识图谱的问答平台&#xff0c;旨在为用户提供快速、准确的百科知识查询服务。系统通过爬…

stm32rtc实时时钟详解文章

目录 stm32 后备区域基础知识详解 stm32 bkp基础知识详解 Unix时间戳基础知识详解 stm32 rtc实时时钟基础知识详解 相关代码初始化配置 欢迎指正&#xff0c;希望对你&#xff0c;有所帮助&#xff01;&#xff01;&#xff01; stm32 后备区域基础知识详解 stm32芯片的 …

Spring Boot项目@Cacheable注解的使用

Cacheable 是 Spring 框架中用于缓存的注解之一&#xff0c;它可以帮助你轻松地将方法的结果缓存起来&#xff0c;从而提高应用的性能。下面详细介绍如何使用 Cacheable 注解以及相关的配置和注意事项。 1. 基本用法 1.1 添加依赖 首先&#xff0c;确保你的项目中包含了 Spr…

windows上vscode cmake工程搭建

安装vscode插件&#xff1a; 1.按装fastc&#xff08;主要是安装MinGW\mingw64比较方便&#xff09; 2.安装C&#xff0c;cmake&#xff0c;cmake tools插件 3.准备工作完成之后&#xff0c;按F1&#xff0c;选择cmake:Quick Start就可以创建一个cmake工程。 4.设置Cmake: G…

SpringMVC详解

文章目录 1 什么是MVC 1.1 MVC设计思想1.2 Spring MVC 2 SpringMVC快速入门3 SpringMVC处理请求 3.1 请求分类及处理方式 3.1.1 静态请求3.1.2 动态请求 3.2 处理静态请求 3.2.1 处理html文件请求3.2.2 处理图片等请求 3.3 处理动态请求 3.3.1 注解说明3.3.2 示例 3.4 常见问题…

【用deepseek和chatgpt做算法竞赛】——还得DeepSeek来 -Minimum Cost Trees_5

往期 【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_0&#xff1a;介绍了题目和背景【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_1&#xff1a;题目输入的格式说明&#xff0c;选择了邻接表…

面试题汇总

1. 判断大小端问题 大端&#xff1a;低字节存放在高地址&#xff1b; 小端&#xff1a;低字节存放在低地址 如 : 0x12345678 bool is_little_endian() {unsigned int x 1;return ((char*)&x)[0]; }bool is_big_endian() {unsigned int x 1;return !((char*)&x)[0];…