环境:Unity2021.1.14 Odin3.0.4 语言:C#

面向:UnityEditor/Odin进阶开发人员

总起

我们在前两篇文章中讲解了Unity中Undo原理并进行了实现,这次我们来看看Odin是如何接入Undo。

实际上Odin本身是基于Unity的IMGUI,所以它Undo的底层实现就是使用的Unity中的Undo。

Odin实现Undo

先来看看以下实现:

using System;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using UnityEngine;public class TestOdinUndo : MonoBehaviour
{private TestOdinUndoData testOdinUndoData = new TestOdinUndoData();private PropertyTree _propertyTree;public PropertyTree propertyTree{get{if (_propertyTree == null){_propertyTree = PropertyTree.Create(testOdinUndoData);}return _propertyTree;}}[OnInspectorGUI]public void OnInspectorGUI(){propertyTree.Draw(false);}
}[Serializable]
public class TestOdinUndoData
{public int iValue;
}

效果如下,iValue能够正确显示出来,不过Undo功能因为Draw中传的是false所以没有生效。

接下来我们尝试在外面包裹一层ScriptableObject转成Unity的Object,再包裹一层SerializedObject进行传入:

using System;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using UnityEditor;
using UnityEngine;public class TestOdinUndo : MonoBehaviour
{// 包裹的第二层,SerializedObject内部是序列化的数据,方便Unity处理private SerializedObject _serializedObject;public SerializedObject serializedObject{get{if (_serializedObject == null){_serializedObject = new SerializedObject(testOdinUndoWrapData);}return _serializedObject;}}// 包裹的第一层,是个ScriptableObjectprivate TestOdinUndoWrapData _testOdinUndoWrapData;private TestOdinUndoWrapData testOdinUndoWrapData{get{if (_testOdinUndoWrapData == null){_testOdinUndoWrapData = ScriptableObject.CreateInstance<TestOdinUndoWrapData>();_testOdinUndoWrapData.data = testOdinUndoData;}return _testOdinUndoWrapData;}}private TestOdinUndoData testOdinUndoData = new TestOdinUndoData();private PropertyTree _propertyTree;public PropertyTree propertyTree{get{if (_propertyTree == null){// 创建PropertyTree使用SerializedObject_propertyTree = PropertyTree.Create(serializedObject);}return _propertyTree;}}[OnInspectorGUI]public void OnInspectorGUI(){// 调用Draw,传入truepropertyTree.Draw(true);}
}public class TestOdinUndoWrapData : ScriptableObject
{public TestOdinUndoData data;
}[Serializable]
public class TestOdinUndoData
{public int iValue;
}

按照以上即可实现Undo的功能。

事实上Unity Inspector处理各个字段绘制时也使用的是SerializedObject,我们在使用IMGUI写Editor时Unity也是建议使用该对象的。

Odin的序列化

我们先来看以下代码:

using Sirenix.OdinInspector;public class TestOdinSerialize : SerializedMonoBehaviour
{public int iValue;public float fValue;
}

把它做成Prefab保存,我们可以看到iValue和fValue都是由Unity本身进行序列化的:

使用OdinSerialize标签:

using Sirenix.OdinInspector;
using Sirenix.Serialization;public class TestOdinSerialize : SerializedMonoBehaviour
{[OdinSerialize]public int iValue;public float fValue;
}

保存后结果:

可以看到Odin序列化中也出现了iValue字段,同时Unity也会序列化该字段。

我们通过Serialization Debugger也可以看到该结果。

想要禁用Unity的序列化只需要打上NonSerialized,这样就只会有Odin的序列化:

using System;
using Sirenix.OdinInspector;
using Sirenix.Serialization;public class TestOdinSerialize : SerializedMonoBehaviour
{[NonSerialized][OdinSerialize]public int iValue;public float fValue;
}

总结一下:

  1. Unity能序列化的字段,Odin不会主动序列化;
  2. 使用OdinSerialize和NonSerialized两个标签强制使用Odin序列化;
  3. 当Unity和Odin都能序列化的时候,则会产生两份序列化数据,所以要想好使用哪种序列化,可以使用Serialization Debugger进行确认。

然后根据官网整理了两个重点:

  1. 当子对象中有需要Odin的序列化时,需要从父对象一路下来都要指定为Odin序列化,否则会使用Unity的序列化;
  2. Odin序列化的是最佳实践是:尽量使用Unity的序列化,因为Odin的序列化会产生两次序列化过程比较消耗性能。

Odin序列化的一些细节

Odin在处理序列化时实际上是把数据转存到SerializationData上。

在默认情况下会有一个List<SerializationNode>记录想要序列化的数据,然后再由Unity进行序列化,这是之前说的Odin会产生两次序列化过程的本质。

针对这套流程我做了一个简单的小实验:

List<SerializationNode> nodes = new List<SerializationNode>();
nodes.Add(new SerializationNode() {Name = "iValue", Entry = EntryType.Integer, Data = "3"});using (var context = Cache<DeserializationContext>.Claim())
using (var reader = new SerializationNodeDataReader(context))
using (var resolver = Cache<UnityReferenceResolver>.Claim())
{reader.Nodes = nodes;context.Value.IndexReferenceResolver = resolver.Value;UnitySerializationUtility.DeserializeUnityObject(this, reader);
}

执行这套流程,我们可以看到iValue变成3。

通过这样的实现我们主动构建了这套Node的List,然后再进行反序列化到对象上。

或许通过这套流程我们能实现json转成Node保存到Unity asset中?我还没有做更加深入的研究,或许等哪天需要吧,这边暂时只提一个思路。

Unity3D Editor Undo回退效果实现3 Odin相关相关推荐

  1. Unity3D Editor 编辑器扩展3 Editor脚本

    Unity3D Editor 编辑器扩展3 Editor脚本 环境:Unity2017.2 语言:C# 总起: 在编辑Unity项目的时候,总不可能避免的接触到Unity自身自带的Inspector参 ...

  2. 【Unity3D Editor】导入图片自动转换成Sprite

    [Unity3D Editor]导入图片自动转换成Sprite https://blog.csdn.net/july_unity/article/details/79275097 一,导入 1,无论是 ...

  3. Unity3d 实现落叶飘效果

    Unity3d 实现落叶飘效果 一. 演示效果: 1.gif图演示 2.视频演示 二.快速开始 1.下载插件 2.使用教程 三.代码概述: 1.LeavesLife.cs 2.LeavesSpwan. ...

  4. Unity3d实现翻书效果

    Unity3d实现翻书效果 此教程需要用到Book-Page Curl Pro插件,unity商店里有,需要插件和工程的话留邮箱 1.将插件中的bookPro复制成自己的prefab,将page0和p ...

  5. ## Unity3D实现粒子光环效果

    Unity3D实现粒子光环效果 参考效果: http://i-remember.fr/en 基本思路如下 1. 使用unity3d自带的粒子系统 2. 为圆环设置最大半径maxR和最小半径minR 3 ...

  6. emc整改措施及案例_我们推荐EMC整改效果_EMC整改方案相关

    由于产品前期没有进行EMC设计或者考虑不周,以及市场对产品的EMC要求越来越严格.企业在进行产品EMC认证的过程中往往会出现部分EMC项目无法通过,而且在短时间内需要寻找问题根源并解决问题.针对企业的 ...

  7. Unity3D Editor 编辑器扩展2 选取物体、撤销操作和窗口小部件的显示

    环境:Unity2017.2 语言:C# 总起: 今天主要介绍以下内容: 1.通过MenuCommand.Selection获取选中对象: 2.通过Undo编写可撤销的命令: 3.窗口小部件的显示. ...

  8. Unity3D Editor 扩展

    官方教程:链接 EditorLayout API:链接 Handles API:链接 1.首先来个Inspector面板Editor的实现 要实现一个组件在Inspector中的Editor功能,首先 ...

  9. 【Unity3d Shader】景深效果

    摄影常用的一招就是背景虚化,背景虚化的相片可以突出拍摄主题,强调自己要展现的事物. 摄影技巧为:1,开大光圈:2,拉长焦距:3,主体离镜头近:4,背景离主体远 有了背景虚化,照片会变的有艺术感见下图( ...

  10. Unity3D——添加剑痕效果(PocketRPG Trail插件)

    首先非常感谢大家的支持,由于最近项目吃紧,所以更新的速度可能会有点慢!希望大家谅解,当然大家的支持是我最大的动力,我也会尽我所能写出更好的文章,当然由于本人是个新手而且工作的内容也不是unity3D, ...

最新文章

  1. java字符串去掉空格
  2. 中国发现银河系最大恒星级黑洞!颠覆认知登上Nature:68倍太阳质量,自研郭守敬望远镜立大功...
  3. Win10 插入耳机无声问题 解决办法
  4. julia 调用python库_Julia调用Python实现超像素分割SLIC算法
  5. php中文网第七期课程目录,php中文网第七期
  6. 【渝粤题库】国家开放大学2021春1359高级英语写作题目
  7. 阅读react-redux源码 - 一
  8. 写一个函数取出php,写一个函数,尽可能高效的,从一个标准 url 里取出文件的扩展名...
  9. C# EntityFramework连接MySQL (DbFirst)
  10. 百度愚人节恶搞背后的趋势
  11. es6 Class 的 Generator函数
  12. 由于3²+4²=5²,所以称‘3,4,5‘为勾股数,求n(包括n)以内所有勾股数数组。
  13. 京东黑科技引爆车联网时代 你的爱车升级了吗?
  14. MyEclipse SVN插件的安装
  15. 什么软件能做英语测试卷听力,英语听力app哪个好用-什么英语听力软件最好
  16. 低级鼠标钩子WH MOUSE LL
  17. 2021 年人工智能全球最具影响力学者榜单 AI 2000 发布
  18. hmailserver的反垃圾邮件功能
  19. 【方法论】时间管理矩阵(Time Management Matrix )-给事情排序,列好1234再执行吧!
  20. 【Xilinx】如何根据芯片封装尺寸绘制3D模型

热门文章

  1. mt7621 openwrt19.07 打开uart3
  2. MT7621搭载openwrt实现U盘等设备自动挂载
  3. 串口转WiFi透传模块UART转WiFi模块嵌入式WiFi参数一键配置原理
  4. Spark源码之存储体系简介及缓存cache源码流程图
  5. 异步电机参数计算的公式法
  6. HTC T328W刷机包 仿三星S5 UI美化 精简 S5下拉
  7. 一文回顾腾讯数字生态大会·微搭低代码专场
  8. SKU与SPU的区别与联系
  9. cmd命令 复制文件夹里所有文件到另一个文件夹操作方式
  10. 小型超市管理系统的设计与实现 毕业设计-附源码011136