Odin-Inspector-系列教程—–初识Odin序列化

前言,在Unity开发中,一些挂在物体上的脚本公开的成员变量,可通过inspector面板更改对应的值,但并不是所有公开成员的值,都可以通过inspector面板进行填写,而且有些数值即使填写,也保存不了(无法序列化),例如:Dictionary<Tkey,TValue>。但是Odin为我们提供了一套解决这种情况的序列化方案。

如下图所示,keyValuePairs_0成员和keyValuePairs_1成员都无法进行有效的序列化,虽然keyValuePairs_1通过特性ShowInInspector强制显示出对应的Dictionary,也可以填写,但是在运行时,填写的数据会丢失。

public class ExampleUnitySerializedScript : MonoBehaviour
{
    public Dictionary keyValuePairs_0 = new Dictionary();

    [ShowInInspector]
    public Dictionary keyValuePairs_1 = new Dictionary();
}

使用Odin序列化

使用比较简单,默认情况下我们继承的是 MonoBehaviour,现在我们只需要用SerializedMonoBehaviour代替MonoBehaviour即可,即开即用,非常简单。

public class ExampleUnitySerializedScript : SerializedMonoBehaviour
{
    public Dictionary keyValuePairs_0 = new Dictionary();

    [ShowInInspector]
    public Dictionary keyValuePairs_1 = new Dictionary();
}

对应SerializedMonoBehaviour这类Odin序列化类,总共有以下7种,足以满足日常开发中的绝大多数需求

  • SerializedMonoBehaviour
  • SerializedBehaviour
  • SerializedComponent
  • SerializedNetworkBehaviour
  • SerializedScriptableObject
  • SerializedStateMachineBehaviour
  • SerializedUnityObject

这时有同学会问,Odin序列化是不是强制替换了原有的Unity序列化?有什么需要注意的地方呢?

第一个问题:Odin序列化默认情况是不会替换Unity原有序列化的,Odin序列化仅仅是基于Unity序列化的扩展,对成员进行序列化时,如果Unity支持,就使用Unity序列化,如果不支持,转由Odin序列化接手。

第二个问题:注意事项是有的,就像刚刚的回答,默认的情况下Odin不会替换Unity原有支持的序列化情况,但是我们可以强制使用Odin序列化,或者强制让Unity序列化和Odin序列化并存,当然这种并存也会出现2份数据,所以不建议这么做。如果对这段解答不是很理解,请看下面的示例

示例到代码

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System;
using System.Collections.Generic;
using UnityEngine;

public class ExampleOdinSerializedScript : SerializedMonoBehaviour
{
    // 使用Odin序列化,而非Unity序列化
    public Dictionary firstDictionary= new Dictionary();

    // MyClassByUnity 因为标记为 Serializable ,所以使用Unity 自带的序列化,而非Odin 序列化
    public MyClassByUnity myUnityReference = new MyClassByUnity();

    //强制使用 Odin 序列化,而不使用Unity的序列化
    [NonSerialized, OdinSerialize]
    public MyClassByOdin myOdinReference = new MyClassByOdin();

    private void Start()
    {
        Debug.Log(firstDictionary.Count);
        Debug.Log(myUnityReference.secondDictionary_Unity.Count);
        Debug.Log(myOdinReference.secondDictionary_Odin.Count);
    }

}

[Serializable]
public class MyClassByUnity
{
    // 虽然标记为 OdinSerialize 特性, 但是依然不会被序列化
    [OdinSerialize]
    public Dictionary secondDictionary_Unity = new Dictionary();
}

[Serializable]
public class MyClassByOdin
{
    [OdinSerialize]
    [NonSerialized]
    public Dictionary secondDictionary_Odin= new Dictionary();
}

成员变量firstDictionary是Unity不支持的Dictionary类型,所以默认使用Oidn 序列化,如果强行标记Serializable特性会出现如下报错

成员变量MyUnityReference是MyClassByUnity类型,在MyClassByUnity类中对应的成员SecondDictionary_Unity标记特性OdinSerialize,按常理secondDictionary_Unity字段会使用Odin序列化,但是MyClassByUnity类标记了Serializable特性,所以MyClassByUnity会按照Unity序列化的方式,又因为MyClassByUnity为Unity序列化不支持的类,所以直接跳过。类似一个for循环中,在索引0处执行break,后面的数据不会遍历一样(此处感觉略微啰嗦)。

为了避免上面的情况发生,我们使用[NonSerialized, OdinSerialize]两个特性,这是告诉编辑器,拒绝使用Unity原有的序列化,而是强制使用Odin自带的序列化系统,这样,上面的问题就可迎刃而解。

Odin是一个强大的系统,在后面的章节中笔者会更详细的介绍Odin的序列化系统,如果你感觉Odin不错,就把他推荐给你的同伴吧


更多教程内容详见:革命性Unity 编辑器扩展工具 — Odin Inspector 系列教程

发表评论