Odin学习笔记

Serializer

官网
这个比我写的详细呀Σ>―(〃°ω°〃)♡→

方式一:继承

可以让Monobehaviour继承SerializedMonoBehaviour 或者让ScriptableObject继承SerializedScriptableObject,如下所示可以把属性和字典序列化并在Inspector上可编辑。

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ZYF
{
    public class ZYF_Test_DictionaryDrawer : SerializedMonoBehaviour
    {
        [SerializeField]
        private object SerializedPrivateField;

        public object SerializedField;

        [OdinSerialize]
        public object SerializedProperty { get; set; }

        public Dictionary<int, GameObject> SerializedDic;

    }

}

在这里插入图片描述

方式二:接口

在需要序列化的类上实现接口ISerializationCallbackReceiver,然后再用Odin的UnitySerializationUtility类。
相当于把继承的那部分拆开了,一般来说继承比较方便,不用重复的实现接口。如下所示就可以把字典序列化到Inspector上了。

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ZYF
{
    /// <summary>
    /// 接口方式序列化
    /// </summary>
    [ShowOdinSerializedPropertiesInInspector]
    public class ZYF_CustomSerializedMonoBehaviour : MonoBehaviour, ISerializationCallbackReceiver, ISupportsPrefabSerialization
    {
        public Dictionary<int, string> dic;
        #region 序列化
        [SerializeField, HideInInspector]
        private SerializationData serializationData;
        SerializationData ISupportsPrefabSerialization.SerializationData { get { return this.serializationData; } set { this.serializationData = value; } }

        void ISerializationCallbackReceiver.OnAfterDeserialize()
        {
            UnitySerializationUtility.DeserializeUnityObject(this, ref this.serializationData);
        }

        void ISerializationCallbackReceiver.OnBeforeSerialize()
        {
            UnitySerializationUtility.SerializeUnityObject(this, ref this.serializationData);
        }
        #endregion
    }

}

在这里插入图片描述

保存与读取序列化数据

网址
我们无法保存Unity Object,因此保存玩家数据时要把数据与Unity Object相关的分离开,可以把数据放到一个单独的类中,只对这个类对象进行序列化数据的保存读取操作。

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace ZYF
{
    public class ZYF_Test_SaveGameData_Player : MonoBehaviour {
        [System.Serializable]
        public class PlayerState {
            public Vector3 position;
            public float health;
            public List<Item> inventory;
        }
        [System.Serializable]
        public class Item {
            public string id;
            public int count;
        }

        [SerializeField,HideInInspector]
        private PlayerState state = new PlayerState();
        [ShowInInspector]
	    public float Health {
            get => this.state.health;
            set => this.state.health = value;
        }
        [ShowInInspector]
        public List<Item> Inventory {
            get => this.state.inventory;
            set => this.state.inventory = value;
        }
        string path => Application.dataPath + "/playerStateData.d";

        private void OnEnable()
        {

            LoadState(path);
        }
        private void OnDisable()
        {
            SaveState(path);
        }
        public void SaveState(string filePath) {
            this.state.position = transform.position;
            byte[] bytes = SerializationUtility.SerializeValue(this.state,DataFormat.Binary);
            File.WriteAllBytes(filePath,bytes);
            Debug.Log($"保存数据:{filePath}");
        }
        public void LoadState(string filePath) {
            if (!File.Exists(filePath))
            {
                return;
            }
            byte[] bytes = File.ReadAllBytes(filePath);
            this.state = SerializationUtility.DeserializeValue<PlayerState>(bytes,DataFormat.Binary);
            this.transform.position = this.state.position;
            Debug.Log($"读取数据:{filePath}");

        }
    } 

}

Unity 序列化方案了解下

On Unitys Serialization Protocol
1.Unity 序列化方案非常简单直接,这样可以非常快的序列化和反序列化。
2.只有被Serializable特性标识才能被Unity序列化。

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ZYF
{
    public class ZYF_Test_SerializationDebugger : MonoBehaviour
    {

        public TypeWithoutSerializable NotSerialized;

        public TypeWithSerializable Serialized;
        public class TypeWithoutSerializable {  }

        [Serializable]
        public class TypeWithSerializable { }
    }

}

3.任何泛型类变量都不能被Unity序列化(List<T>除外),但是继承自该泛型类的非泛型子类可以。

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ZYF
{
    public class ZYF_Test_SerializationDebugger : MonoBehaviour
    {

       public MyGenericClass<int> NonSerialized;

         public MyIntClass Serialized;

        public List<int> SerializedList; 

        [Serializable]
        public class MyGenericClass<T>
        {
            public T Value;
        }

        [Serializable]
        public class MyIntClass : MyGenericClass<int>
        {
        }
    }

}

4.多态(抽象类,接口,object),不会被序列化。

Odin 序列化方案了解下

On Odins Serialization Protocol
1.Odin对MonoBehaviours,ScriptableObjects…的序列化只是对Unity 序列化的一种扩展
2.Odin把Unity没序列化的字段、属性转成Unity可以序列化的数据格式(SerializationData)。
3.当然这种方案有可能会把一个字段序列化两次(Unity+Odin),不过Odin已经做了处理过滤掉了已经被Unity序列化的那些字段,可以用Serialization Debugger查看脚本的序列化情况。
4.当然了Unity方案简单而且比Odin快的多,如果可以还是不用Odin的序列化哈
5.Odin不会覆盖Unity已序列化的部分

序列化相关的特性

1.[NonSerialized, OdinSerialize]:强制使用Odin序列化方案而不用Unity的方案;

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ZYF
{
    public class ZYF_Test_SerializationDebugger : SerializedMonoBehaviour {

        // Unity 负责序列化这个字段但是不会序列化该对象内部的‘MyDictionary’字段
        public MySerializedObject UnitySerialized;

        // 只使用Odin序列化这个字段,并且内部的‘MyDictionary’也会被序列化保存。
        [NonSerialized, OdinSerialize]
        public MySerializedObject OdinSerialized;

        //也可以把这个特性去掉而不用上面的NonSerialized特效屏蔽Unity的序列化
        [Serializable]
        public class MySerializedObject
        {
            //[NonSerialized, OdinSerialize]等类似的特性在这里没啥作用,因为序列化只取决于根级别序列化方式
            public Dictionary<int, string> MyDictionary;
        }
    } 

}

2.[ShowInInspector]:可以显示所有字段或属性(包括静态的),但是它的功能只是让字段或属性的值在Inspector上显示而已,并不能序列化它们切记!

using Sirenix.OdinInspector;
using Sirenix.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ZYF
{
    public class ZYF_Test_SerializationDebugger : SerializedMonoBehaviour
    {

        [ShowInInspector]
        private int myPrivateInt;

        [ShowInInspector]
        public int MyPropertyInt { get; set; }

        [ShowInInspector]
        public int ReadOnlyProperty
        {
            get { return this.myPrivateInt; }
        }

        [ShowInInspector]
        public static bool StaticProperty { get; set; }
    }

}

好多神奇的特性

官网
访问时需要添加using Sirenix.OdinInspector;

FilePath

可以提取你在inspector中选择的文件的路径。

Button

可以把方法暴露在inspector上。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {
        [FilePath(Extensions =".unity")]
        public string scenePath;
        [Button(ButtonSizes.Large)]
        public void SayHello() {
            Debug.Log("Hello button");
        }
    } 

}

在这里插入图片描述

HideInInspector

隐藏字段

ShowInInspector

显示字段(包含静态)及属性(包含静态)的值(如果没有被序列化修改它们是无效的!!)
在这里插入图片描述

PreviewField

添加预览框

Required

如果目标是空的就会提示

AssetsOnly

限定从Project中选择而不是从Scene中

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {
        [PreviewField(Height =200),Required,AssetsOnly]
        public GameObject prefab;
    } 

}

在这里插入图片描述

PropertyOrder

可以重新排列字段或属性在Inspector上的显示顺序。

HideLabel

隐藏Inspector上显示的标签。
在这里插入图片描述

HorizontalGroup&VerticalGroup

HorizontalGroup:定义一个水平分组,指定了group后可以使用VerticalGroup把该水平分组分割成垂直分组,VerticalGroup需要指定groupid为HorizontalGroup定义时的group+‘/’+VerticalGroupId

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {
        [HorizontalGroup("Split", Width = 50), HideLabel, PreviewField(50)]
        public Texture2D icon;

        #region VerticalGroup:Split/Properties

        [VerticalGroup("Split/Properties")]
        public string minionName;

        [VerticalGroup("Split/Properties")]
        public string health;

        [VerticalGroup("Split/Properties")]
        public string demage;
        #endregion
        
        #region VerticalGroup:Split/Properties1

        [VerticalGroup("Split/Properties1")]
        public string minionName1;

        [VerticalGroup("Split/Properties1")]
        public string health1;

        [VerticalGroup("Split/Properties1")]
        public string demage1;
        #endregion

        
    } 

}

在这里插入图片描述

引用字段值($或@)

如下所示可以把iAmLabel的标签内容引用为该字段的值。

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {
        [LabelText("$iAmLabel")]
        public string iAmLabel;
    } 

}

在这里插入图片描述

引用方法(ListDrawerSettings)

如下所示CustomAddFunction:指定在Inspector添加一个item时执行对应绑定的方法CreateNewGUID;
CustomRemoveIndexFunction:指定在Inspector移除一个item时执行对应绑定的方法RemoveGUID

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {

        [ListDrawerSettings(CustomAddFunction ="CreateNewGUID",CustomRemoveIndexFunction ="RemoveGUID")]
        public List<string> guidList;
        private string CreateNewGUID() {
            return Guid.NewGuid().ToString();
        }
        private void RemoveGUID(int index) {
            this.guidList.RemoveAt(index);
        }
    } 

}

在这里插入图片描述

GroupAttributes

TabGroup

如果在Inspector上有一堆的变量,可以用TabGroup对它们进行分组保持界面整洁。

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {

        [TabGroup("Tab group 0")]
        public int firstTab;

        [ShowInInspector,TabGroup("Tab group 0")]
        public int SecondTab { get; set; }

        [TabGroup("Tab group 1")]
        public float floatValue;

        [TabGroup("Tab group 1"),Button]
        public void Button() {
            floatValue++;
        }
    } 

}

在这里插入图片描述

FoldoutGroup

创建一个可折叠的组。

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour {

        [Button(ButtonSizes.Large)]
        [FoldoutGroup("Buttons in Boxes")]
        [HorizontalGroup("Buttons in Boxes/Horizontal", Width = 60)]
        [BoxGroup("Buttons in Boxes/Horizontal/One")]
        public void Button1() { }

        [Button(ButtonSizes.Large)]
        [BoxGroup("Buttons in Boxes/Horizontal/Two")]
        public void Button2() { }

        [Button]
        [BoxGroup("Buttons in Boxes/Horizontal/Double")]
        public void Accept() { }

        [Button]
        [BoxGroup("Buttons in Boxes/Horizontal/Double")]
        public void Cancel() { }
    } 

}

在这里插入图片描述

创建自定义分组(设置背景色)

官网
功能:创建自定义的ColorGroupAttribute,可以设置每一组的背景色,效果如下所示:
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour
    {
        [ZYF_Test_ColoredFoldoutGroup("group 0", 1, 0, 0)]
        public int test;
        [ZYF_Test_ColoredFoldoutGroup("group 0")]
        public int test1;
        [ZYF_Test_ColoredFoldoutGroup("group 1", 0, 0, 1)]
        public int test2;
        [ZYF_Test_ColoredFoldoutGroup("group 1")]
        public int test3;
    }

}

步骤:
1.继承PropertyGroupAttribute

using Sirenix.OdinInspector;
using UnityEngine;

namespace ZYF
{
    public class ZYF_Test_ColoredFoldoutGroupAttribute : PropertyGroupAttribute
    {
        public float r, g, b, a;
        public ZYF_Test_ColoredFoldoutGroupAttribute(string groupId) : base(groupId)
        {

        }

        public ZYF_Test_ColoredFoldoutGroupAttribute(string groupId, float r, float g, float b, float a = 1f) : base(groupId)
        {
            this.r = r;
            this.g = g;
            this.b = b;
            this.a = a;
        }
        protected override void CombineValuesWith(PropertyGroupAttribute other)
        {
            var otherAttr = other as ZYF_Test_ColoredFoldoutGroupAttribute;
            this.r = Mathf.Max(otherAttr.r, this.r);
            this.g = Mathf.Max(otherAttr.g, this.g);
            this.b = Mathf.Max(otherAttr.b, this.b);
            this.a = Mathf.Max(otherAttr.r, this.a);
        }
    }

}

2.在Editor文件夹下新建Drawer(继承OdinGroupDrawer),绘制Inspector。

using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using UnityEngine;
namespace ZYF
{
    public class ZYF_ColoredFoldoutGroupAttributeDrawer : OdinGroupDrawer<ZYF_Test_ColoredFoldoutGroupAttribute>
    {
        private LocalPersistentContext<bool> isExpanded;
        protected override void Initialize()
        {
            this.isExpanded = this.GetPersistentValue<bool>(key: $"{nameof(ZYF_ColoredFoldoutGroupAttributeDrawer)}.{nameof(isExpanded)}", defaultValue:
                GeneralDrawerConfig.Instance.ExpandFoldoutByDefault);
        }
        protected override void DrawPropertyLayout(GUIContent label)
        {
            //box背景颜色修改
            GUIHelper.PushColor(new Color(this.Attribute.r, this.Attribute.g, this.Attribute.b, this.Attribute.a));
            SirenixEditorGUI.BeginBox();
            GUIHelper.PopColor();

            //折叠按钮
            SirenixEditorGUI.BeginBoxHeader();
            this.isExpanded.Value = SirenixEditorGUI.Foldout(this.isExpanded.Value, label);
            SirenixEditorGUI.EndBoxHeader();

            //组内Item绘制
            if (SirenixEditorGUI.BeginFadeGroup(this, this.isExpanded.Value))
            {
                for (int i = 0; i < this.Property.Children.Count; i++)
                {
                    this.Property.Children[i].Draw();
                }
            }
            SirenixEditorGUI.EndFadeGroup();

            SirenixEditorGUI.EndBox();
        }

    }
}

Meta Attributes

Meta 特性可以在值改变时做输入验证,方法调用等等…

ValidateInput

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour
    {
        [ValidateInput("IsValid")]
        public int greaterThanZero;
        private bool IsValid(int value) {
            return value > 0;
        }
    }

}

在这里插入图片描述

OnValueChanged

using Sirenix.OdinInspector;
using UnityEngine;

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour
    {
        [OnValueChanged("UpdateRigidbody"), PreviewField]
        public GameObject prefab;
        [SerializeField]
        private Rigidbody prefabRigidbody;
        private void UpdateRigidbody(GameObject prefab)
        {
            if (prefab != null)
            {
                prefabRigidbody = prefab.GetComponent<Rigidbody>();
            }
            else
            {
                prefabRigidbody = null;
            }
        }
    }

}

在这里插入图片描述

Required

引用丢失或为空时会有警告提示。

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour
    {
        [Required,PreviewField]
        public GameObject prefab;
        
    }

}

在这里插入图片描述

InfoBox

显示信息提示。

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour
    {
        [InfoBox( message:"这条消息只有在myInt是偶数时才显示",visibleIfMemberName:"IsEven")]
        public int myInt;
        private bool IsEven() {
            return this.myInt % 2 == 0;
        }
    }

}

在这里插入图片描述

PropertyOrder

可以改变在Inspector上的显示顺序,降序排列。

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

namespace ZYF
{
    public class ZYF_Test_OdinAttributes : MonoBehaviour
    {
        [PropertyOrder(1)]
        public int Last;

        [PropertyOrder(-1)]
        public int First;

        //默认为0
        public int Middle;

        [Button]
        [PropertyOrder(-2)]
        public void FirstMethod()
        {
            // ...
        }
    }

}

在这里插入图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牙膏上的小苏打2333

哟,哟,切克闹,煎饼果子来一套

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值