Unity3D Editor Undo回退效果实现3 Odin相关
环境: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;
}
总结一下:
- Unity能序列化的字段,Odin不会主动序列化;
- 使用OdinSerialize和NonSerialized两个标签强制使用Odin序列化;
- 当Unity和Odin都能序列化的时候,则会产生两份序列化数据,所以要想好使用哪种序列化,可以使用Serialization Debugger进行确认。
然后根据官网整理了两个重点:
- 当子对象中有需要Odin的序列化时,需要从父对象一路下来都要指定为Odin序列化,否则会使用Unity的序列化;
- 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相关相关推荐
- Unity3D Editor 编辑器扩展3 Editor脚本
Unity3D Editor 编辑器扩展3 Editor脚本 环境:Unity2017.2 语言:C# 总起: 在编辑Unity项目的时候,总不可能避免的接触到Unity自身自带的Inspector参 ...
- 【Unity3D Editor】导入图片自动转换成Sprite
[Unity3D Editor]导入图片自动转换成Sprite https://blog.csdn.net/july_unity/article/details/79275097 一,导入 1,无论是 ...
- Unity3d 实现落叶飘效果
Unity3d 实现落叶飘效果 一. 演示效果: 1.gif图演示 2.视频演示 二.快速开始 1.下载插件 2.使用教程 三.代码概述: 1.LeavesLife.cs 2.LeavesSpwan. ...
- Unity3d实现翻书效果
Unity3d实现翻书效果 此教程需要用到Book-Page Curl Pro插件,unity商店里有,需要插件和工程的话留邮箱 1.将插件中的bookPro复制成自己的prefab,将page0和p ...
- ## Unity3D实现粒子光环效果
Unity3D实现粒子光环效果 参考效果: http://i-remember.fr/en 基本思路如下 1. 使用unity3d自带的粒子系统 2. 为圆环设置最大半径maxR和最小半径minR 3 ...
- emc整改措施及案例_我们推荐EMC整改效果_EMC整改方案相关
由于产品前期没有进行EMC设计或者考虑不周,以及市场对产品的EMC要求越来越严格.企业在进行产品EMC认证的过程中往往会出现部分EMC项目无法通过,而且在短时间内需要寻找问题根源并解决问题.针对企业的 ...
- Unity3D Editor 编辑器扩展2 选取物体、撤销操作和窗口小部件的显示
环境:Unity2017.2 语言:C# 总起: 今天主要介绍以下内容: 1.通过MenuCommand.Selection获取选中对象: 2.通过Undo编写可撤销的命令: 3.窗口小部件的显示. ...
- Unity3D Editor 扩展
官方教程:链接 EditorLayout API:链接 Handles API:链接 1.首先来个Inspector面板Editor的实现 要实现一个组件在Inspector中的Editor功能,首先 ...
- 【Unity3d Shader】景深效果
摄影常用的一招就是背景虚化,背景虚化的相片可以突出拍摄主题,强调自己要展现的事物. 摄影技巧为:1,开大光圈:2,拉长焦距:3,主体离镜头近:4,背景离主体远 有了背景虚化,照片会变的有艺术感见下图( ...
- Unity3D——添加剑痕效果(PocketRPG Trail插件)
首先非常感谢大家的支持,由于最近项目吃紧,所以更新的速度可能会有点慢!希望大家谅解,当然大家的支持是我最大的动力,我也会尽我所能写出更好的文章,当然由于本人是个新手而且工作的内容也不是unity3D, ...
最新文章
- java字符串去掉空格
- 中国发现银河系最大恒星级黑洞!颠覆认知登上Nature:68倍太阳质量,自研郭守敬望远镜立大功...
- Win10 插入耳机无声问题 解决办法
- julia 调用python库_Julia调用Python实现超像素分割SLIC算法
- php中文网第七期课程目录,php中文网第七期
- 【渝粤题库】国家开放大学2021春1359高级英语写作题目
- 阅读react-redux源码 - 一
- 写一个函数取出php,写一个函数,尽可能高效的,从一个标准 url 里取出文件的扩展名...
- C# EntityFramework连接MySQL (DbFirst)
- 百度愚人节恶搞背后的趋势
- es6 Class 的 Generator函数
- 由于3²+4²=5²,所以称‘3,4,5‘为勾股数,求n(包括n)以内所有勾股数数组。
- 京东黑科技引爆车联网时代 你的爱车升级了吗?
- MyEclipse SVN插件的安装
- 什么软件能做英语测试卷听力,英语听力app哪个好用-什么英语听力软件最好
- 低级鼠标钩子WH MOUSE LL
- 2021 年人工智能全球最具影响力学者榜单 AI 2000 发布
- hmailserver的反垃圾邮件功能
- 【方法论】时间管理矩阵(Time Management Matrix )-给事情排序,列好1234再执行吧!
- 【Xilinx】如何根据芯片封装尺寸绘制3D模型