Unity Odin从入门到精通(四):序列化调试器详解

什么是序列化和反序列化:序列化和反序列化主要用来解决对象的传输问题。其中序列化用来将对象转换成二进制流;反序列化用来将二进制流转换成对象。

Unity序列化:Unity序列化器的实现十分简单,目的是为了非常快速的进行序列化和反序列化操作。具有以下特性:
1.可以被序列化的类型如下所示:
1.1.某些Unity内置类型。如:Vector2、Vector3、Vector4、Rect、Quaternion、Matrix4x4、Color、Color32、LayerMask、AnimationCurve、Gradient、RectOffset、GUIStyle、UnityEvent。
1.2.某些C#基元类型。如:sbyte、byte、short、ushort、int、uint、long、ulong、float、double、char、string、bool。
1.3.某些基础枚举类型。在Unity5.6之前,只支持byte和int枚举类型。在Unity5.6之后,只支持sbyte、byte、short、ushort、int、uint枚举类型。
1.4.使用SerializableAttribute定制特性应用的自定义结构体类型。
1.5.继承自UnityEngine.Object的自定义引用类型。
1.6.使用SerializableAttribute定制特性应用的自定义引用类型,并且该自定义引用类型不能使用static、abstract修饰符。
1.7.某些容器类型。如:上述类型的一维数组、List类型。
2.当自定义结构体类型或者自定义引用类型实现了ISerializationCallbackReceiver接口的时,就可以在OnBeforeSerialize函数里面实现序列化之前的操作以及在OnAfterDeserialize函数里面实现反序列化之后的操作。
3.可以使用JsonUtility的ToJson函数来将可序列化类型的实例进行序列化成json格式串,也可以使用JsonUtility的FromJson或者FromJsonOverwrite函数来将json格式串反序列化成可序列化类型的实例。
4.类型中可以被序列化的成员只有字段。具有以下特性:
4.1.可以使用NonSerializedAttribute定制特性来让字段不能被序例化。
4.2.要想字段被成功的序列化,那么首先该字段就不能应用NonSerializedAttribute定制特性。接着该字段所对应的类型必须是可以序列化的类型。然后该字段不能使用static、const、readonly修饰符。最后该字段必须使用public访问权限或者SerializeFieldAttribute定制特性。
4.3.检视面板上会显示序列化成功的字段。
4.4.可以使用HideInInspectorAttribute定制特性来让序列化成功的字段在检视面板上面隐藏起来。
4.5.Unity序列化器不支持序列化多态情况。当字段接收子类实例赋值时,如果该字段可以被成功的序列化,那么该字段也就只能序列化基类部分。
4.6.Unity序列化器不支持序列化空引用数值情况。当字段在进行序列化时,如果该字段对应类型里面存在空引用数值,那么Unity序列化器首先就会通过该空引用数值对应类型的构造函数来创建一个实例;然后通过该实例来替换该空引用数值。
参考代码如下所示:

[Serializable]
public class NodeA
{
    public NodeB nodeB = null;
}

[Serializable]
public class NodeB
{
    public int value = 10;
}

public class MTest : MonoBehaviour
{
    public NodeA nodeA;
}

空引用数值被具体实例替换的效果如下图所示:
在这里插入图片描述
4.7.Unity序列化器不支持序列化循环引用情况。当字段对应的类型存在循环引用自身类型时,为了避免无线循环下去,Unity就会限制最大循环深度为10。在达到这个最大循环深度之前,Unity会出现严重的卡顿。
参考代码如下所示:

[Serializable]
public class NodeA
{
    public NodeB Cycle;
}

[Serializable]
public class NodeB : NodeA
{
    
}

public class MTest : MonoBehaviour
{
    public NodeB Node;
}

深度限制警告如下图所示:
在这里插入图片描述
4.8.Unity序列化器不支持序列化字典类型情况。要想字典类型的字段被成功的序列化,那么就需要将字典类型的key和value各自存储成List类型来进行序列化。参考代码如下所示:

[Serializable]
public class UnitySerializedDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
    [SerializeField, HideInInspector]
    private List<TKey> keyData = new List<TKey>();
	
    [SerializeField, HideInInspector]
    private List<TValue> valueData = new List<TValue>();

    void ISerializationCallbackReceiver.OnAfterDeserialize()
    {
        this.Clear();
        for (int i = 0; i < this.keyData.Count && i < this.valueData.Count; i++)
        {
            this[this.keyData[i]] = this.valueData[i];
        }
    }

    void ISerializationCallbackReceiver.OnBeforeSerialize()
    {
        this.keyData.Clear();
        this.valueData.Clear();

        foreach (var item in this)
        {
            this.keyData.Add(item.Key);
            this.valueData.Add(item.Value);
        }
    }
}

4.9.可以使用FormerlySerializedAsAttribute定制特性来将旧字段的序列化数据映射到新的字段上。
5.交互层具有以下特性:
5.1.首先将C++ Native层中存储的序列化字段的数值进行反序列化并同步到C# 控制层。然后就可以在检视面板中看见该序列化字段的数值了。
5.2.如果在脚本文件中修改序列化字段的数值,那么该字段的修改数值即不会被序列化存储到C++ Native层,也不会被同步到C# 控制层。
5.3.如果在检视面板中修改序列化字段的数值,当游戏处于运行状态时,该字段的修改数值只能同步到C# 控制层;否则该字段的修改数值首先会序列化存储到C++ Native层,然后同步显示到C# 控制层。
6.可以使用AssetDatabase.ForceReserializeAssets函数来强制重新序列化指定路径下的所有资源。

Odin序列化:Odin序列化器主要用来扩展Unity序列化器。具有以下特性:
1.Odin内置序列化类型如下所示:
1.1.SerializedUnityObject:该类型表示通过Odin序列化器进行序列化的Unity Object。
1.2.SerializedScriptableObject :该类型表示通过Odin序列化器进行序列化的Unity ScriptableObject 。
1.3.SerializedComponent :该类型表示通过Odin序列化器进行序列化的Unity Component。
1.4.SerializedBehaviour:该类型表示通过Odin序列化器进行序列化的Unity Behaviour。
1.5.SerializedMonoBehaviour:该类型表示通过Odin序列化器进行序列化的Unity MonoBehaviour。
1.6.SerializedStateMachineBehaviour:该类型表示通过Odin序列化器进行序列化的Unity StateMachineBehaviour。
2.Odin自定义序列化类型的流程如下所示:
2.1.首先让类型继承自想要使用的Unity类型。
2.2.然后让类型实现ISerializationCallbackReceiver接口。
2.3.最后在OnBeforeSerialize函数里面使用UnitySerializationUtility类型的SerializeUnityObject函数来实现序列化,在OnAfterDeserialize函数里面使用UnitySerializationUtility.DeserializeUnityObject函数来实现反序列化。
3.使用Odin序列化器来序列化和反序列化任何类型实例的流程如下所示:
3.1.使用SerializationUtility类型的SerializeValue函数来对指定类型实例按照指定的格式进行序列化,并返回序列化后的字节流。
3.2.使用SerializationUtility类型的DeserializeValue函数来对序列化后的字节流按照指定的格式进行反序列化,并返回指定类型的实例。
3.3.SerializationUtility类型的SerializeValue函数和DeserializeValue函数当中用到的指定格式包含以下几种类型:
3.3.1.Binary:该格式一般在运行模式和构造下使用,主要用来将序列化的数据变成字节流。该格式不仅执行速度很快,而且还会将垃圾分配保持在最低限度。
3.3.2.Json:该格式主要用来将序列化的数据变成人类可以阅读的Json串。由于该格式没有做出任何性能优化,而且还会分配很多不必要的垃圾数据,因此建议还是优先使用性能更加高效的Unity JsonUtility来完成该操作。
3.3.3.Nodes:该格式一般在编辑器模式下使用,主要用来将序列化的数据变成可以和Unity文本资产序列化结合使用的节点列表。该格式的性能比Binary格式稍微差点。
3.4.SerializationUtility类型的SerializeValue函数中用到的指定SerializationContext类型参数以及SerializationUtility类型的DeserializeValue函数中用到的指定DeserializationContext类型参数当中都可以指定外部引用解析器。具有以下特性:
3.4.1.外部引用解析器主要用来对引用对象进行序列化和反序列化。
3.4.2.Odin提供了三种外部引用解析器接口,它们分别是IExternalStringReferenceResolver、IExternalGuidReferenceResolver、IExternalIndexReferenceResolver。
3.4.3.在IExternalStringReferenceResolver接口的CanReference函数当中判断是否将引用对象序列化成一个字符串标识。在IExternalStringReferenceResolver接口的TryResolveReference函数当中判断是否使用指定的字符串标识来反序列化成引用对象。
3.4.4.在IExternalGuidReferenceResolver接口的CanReference函数当中判断是否将引用对象序列化成一个Guid对象。在IExternalGuidReferenceResolver接口的TryResolveReference函数当中判断是否使用指定的Guid对象来反序列化成引用对象。
3.4.5.在IExternalIndexReferenceResolver接口的CanReference函数当中判断是否将引用对象关联到一个指定索引值的列表当中。在IExternalIndexReferenceResolver接口的TryResolveReference函数当中判断是否从列表当中获取指定索引的引用对象。
4.类型中可以被序列化的成员只有字段和属性。具有以下特性:
4.1.要想字段被成功的序列化,那么首先该字段所在的类型就必须继承自Odin内置序列化类型或者Odin自定义序列化类型。然后该字段不能使用static、const修饰符。最后该字段必须使用public访问权限或者SerializeFieldAttribute定制特性或者OdinSerializeAttribute定制特性。
4.2.要想属性被成功的序列化,那么首先该属性所在的类型就必须继承自Odin内置序列化类型或者Odin自定义序列化类型。然后该属性不能使用static修饰符。最后该属性必须使用SerializeFieldAttribute定制特性或者OdinSerializeAttribute定制特性。
4.3.检视面板上会显示序列化成功的字段和属性。
4.4.可以使用HideInInspectorAttribute定制特性来让序列化成功的字段和属性在检视面板上面隐藏起来。
4.5.由于Odin序列化器在执行序列化流程时,首先会将Unity不能序列化的字段和属性转换成Unity可以序列化的数据格式并存储在SerializationData字段中,然后Unity序列化器会将SerializationData字段中存储的数据进行序列化。这样一来,Odin序列化器的执行速度就会低于Unity序列化器。因此,建议优先使用Unity序列化器进行序列化和反序列化操作。
4.6.当不使用OdinSerializeAttribute定制特性来强制使用Odin序列化器时,如果可以使用Unity序列化器来序列化字段,那么就会忽略掉Odin序列化器的序列化操作。
4.7.当字段和属性既能被Unity序列化器进行序列化,也能被Odin序列化器进行序列化时,那么就会得到两份数据,进而会造成内存空间的浪费。
4.8.Odin序列化器在序列化字段和属性时,可以支持多态、空引用数值、循环引用、字典类型等情况。
4.9.可以使用PreviouslySerializedAsAttribute定制特性来将旧字段和属性的序列化数据映射到新的字段和属性上。但是,经过实践表明,该定制特性针对字段而言貌似不起作用。
5.可以使用BindTypeNameToTypeAttribute定制特性在不改变序列化数据的情况下将旧"命名空间.类型"重构成新"命名空间.类型"。
6.在AOT编译平台(如:iOS)上进行序列化时需要注意以下事项:
6.1.Unity的代码剥离设置项不仅无法为泛型变体生成必要代码,而且也会删除序列化系统所需要的某些类。
6.2.Odin AOT自动化功能会为指定的AOT编译平台列表生成一个程序集。该程序集包含运行时环境中所需要的所有序列化功能。使用流程如下所示:
6.2.1.点击【Tools -> Odin Inspector -> Preferences -> AOT Generation】按钮来打开Odin AOT自动化功能界面。
6.2.2.点击Odin AOT自动化功能界面中的【Scan Project】按钮来扫描项目工程,此时Odin就会将项目工程中所有的自定义序列化类型全部显示在【Support Serialized Type】下拉列表中。当然,用户也可以在该下拉列表中手动添加序列化类型条目,但是一般不建议这么做。
6.2.3.点击Odin AOT自动化功能界面中的【Generate DLL】按钮来在Assets/Plugins/Sirenix/Assemblies/AOT/路径下生成一个Sirenix.Serialization.AOTGenerated.dll程序集。
6.2.4.当打包构建项目工程结束后,为了避免不同版本Unity无法解析Sirenix.Serialization.AOTGenerated.dll程序集中某些类型而抛出错误提示,建议将Assets/Plugins/Sirenix/Assemblies/AOT/目录删除掉。此时可以采用以下三种删除方式:
6.2.4.1.手动去项目工程中删除该目录。
6.2.4.2.在打包构建脚本中编写代码来删除该目录。
6.2.4.3.在Odin AOT自动化功能界面中首先勾选【Automate Before Builds】按钮;然后勾选【Delete Dll After Builds】按钮来删除该目录。

序列化调试器:用来调试序列化类型中的成员。具有以下特性:
1.查看序列化调试器的源码:首先在Rider当中切换到Assemblies视图。接着在该视图的列表当中选择Sirenix.OdinInspector.Editor程序集。然后从该程序集的列表当中选择Sirenix.Utilities.Editor命名空间。最后从该命名空间的列表当中双击SerializationDebuggerWindow类型,进而可以查看序列化调试器的源码。如下图所示:
在这里插入图片描述2.打开序列化调试器:如果检视面板上不能正常显示指定类型中成员的数值,那么开发者就可以打开序列化调试器来查看该成员的详细序列化信息。目前存在以下两种打开方式:
2.1.在Unity的菜单栏中选择【Tools -> Odin Inspector -> Serialization Debugger】菜单项来打开序列化调试器。如下图所示:
在这里插入图片描述2.2.首先在检视面板中点击组件按钮来弹出下拉菜单。然后从下拉菜单中选择Debug Serialization菜单项来打开序列化调试器。如下图所示:
在这里插入图片描述3.查看类型成员:首先点击类型按钮来弹出类型下拉列表。然后从类型下拉列表中选择一个类型。最后就可以在展示列表上显示选择类型的成员。如下图所示:
在这里插入图片描述4.序列化类型:支持Unity和Odin两种序列化类型。如下图所示:
在这里插入图片描述
其中每种序列化类型都含有三种状态。如下所示:
4.1.✔表示序列化成功状态。
4.2.✘表示序列化失败状态。如:不支持的序列化类型或者成员。
4.3.!表示序列化警告状态。如:序列化相关的定制特性使用错误。

5.详细信息面板:在选择指定的成员后,就可以在详细信息面板上显示该成员的调试信息。如下图所示:
在这里插入图片描述

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Odin 将催化你的 Unity 工作流程,使它轻易地为你和整个团队构建功能强大并适用于高级用户的编辑器。 Odin 能够完美部署到原有的工作流程中,无需费力的集成工作,让您能够序列化任何内容,并使用 80 多个全新检测器属性、无样板代码和更多功能来使用 Unity! 看看 2.1 版有什么更新! 亮点 - 轻松集成 - 纯编辑器模式 - Odin 编辑器窗口 - 输入验证 - 序列化任何对象 - 强大的列表 - 惊人的扩展性 - 调色板 - 字典 - 还有更多! · 轻松集成: Odin 很容易操作,并且不会打破你的已有工作流程。实际上你甚至不需要继承任何东西,也就是说你的现有编辑器将继续与 Odin 适用。 · 纯编辑器模式: 仅使用 Odin 的编辑器改进,完全禁用序列化。 · Odin 编辑器窗口: 您现在可以使用 Odin 来快速创建自定义的编辑器窗口,帮助组织您的项目和游戏数据。 · 输入验证: 通过允许您的开发者设置场景和输入验证来赋能您的整个团队,让 Unity 的使用对艺术家和开发者来说变得前所未有的容易。 · 序列化任何对象: Odin 使用我们评级很高的自定义序列化协议,让您既可以继承我们的 SerializedBehaviour、SerializedScriptableObject 等,也可以为您已有的类添加几行新代码,让可以序列化的任何内容都得到序列化。是的,甚至是多态类型! 在 2018.3 以上版本中,Odin 序列化的预制件由于嵌套的预制系统而被弃用。 · 功能强大的列表: 所有实现 Microsoft IList 接口的数组和列表均由我们强大的列表绘制器绘制; 拖放、插入和删除单个项目、多维数组、表、交叉列表,甚至是跨窗口的项目拖动、分页、嵌套列表绘制和更多! · 惊人的可扩展性: 强大而灵活的 API 让你轻易扩展和修改检查器的绘制方式。快速创建全新的属性组类型和自定义绘画器! • 更多内容! Odin 还添加了词典、自定义布局、资源列表、值下拉列表、嵌入式编辑器、调色板,甚至更多内容! 平台支持 功能丰富且得到优化的 Odin 序列化器支持: - 桌面 - Android - iOS - WebGL - PlayStation - Xbox - Nintendo Switch - Oculus - 所有的 IL2CPP 平台 - UWP 仅得到 IL2CPP 后端的支持
Unity3D是一款非常流行的游戏引擎,它广泛应用于游戏开发、虚拟现实、增强现实等领域。对于初学者来说,学习Unity3D需要了解其基本概念、操作技巧和流程。为了从入门到精通,需要掌握以下三个阶段: 第一阶段是入门阶段。这个阶段的关键是掌握Unity3D的基本概念和操作方法。首先,需要了解Unity3D的界面结构和菜单命令,熟悉不同面板的功能,包括场景窗口、资源窗口、控制台、层次结构等。其次,需要掌握Unity3D中的对象、组件和预制件的概念。通过学习Object和Component的类结构,了解它们的特性和作用,明白游戏对象的层级关系、物理模拟和碰撞检测等原理。最后,需要掌握脚本编写的基础语法,理解脚本与其他组件的交互方式和生命周期。 第二阶段是中级阶段。在入门阶段的基础上,需要进一步深入了解Unity3D引擎的高级技术和实际应用。主要包括:游戏设计模式、界面布局和UI设计、动画控制和剪辑编辑、材质和着色器的使用、粒子系统和特效处理等。此外,需要了解Unity3D的性能优化和调试方法,运用Profiler、Frame Debugger等工具分析游戏引擎的内部运行机制,减少游戏卡顿和崩溃的情况。 第三阶段是精通阶段。这个阶段的关键是掌握Unity3D引擎的高级特性和复杂游戏的开发流程。主要涉及:脚本优化和高级算法的实现、网络游戏开发和多人游戏场景同步、人工智能和路径规划等。此外,需要了解Unity3D的插件开发和资产管理、持续集成和版本控制、移动平台和AR/VR领域的开发规范等。最终,达到像Unity3D官方开发者一样的能力水平,能够独立完成复杂游戏的开发和运营,或参与到较大规模的团队开发项目中,成为一名优秀的Unity3D开发者。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值