U3D自定义Inspector项未触发保存事件的解决方案
1.问题描述与解决方案
1.1.说明
应该只有起步做U3D编辑器插件的部分同行需要了解本文。
该问题源于在做UI插件的时候,发现Inspector面板上手动修改值后,没有触发U3D编辑器本身的修改事件,导致这次操作无法保存且无法撤销。
修改事件被触发的具体表现为文件名最右边有星号'*',现在大多数文本编辑器中内容改变也基本如此表现。
1.2.解决方案
这里我列出两种解决方案:
(下面都以待修改的对象为PlayerControl类型的obj变量)
public class PlayerControl : MonoBehaviour { public int intVal = 0; public List<int> listVal = new List<int>(); }
1.利用UnityEngine中的Undo类,比如修改obj中类型为int的成员变量intVal:
using UnityEditor; public class test : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); var obj = target as PlayerControl; Undo.RecordObject(obj,"obj change"); obj.intVal = 1; } }
但如果obj中的一个成员变量为引用类型,并且变动的时候引用未变,那么RecordObject就不会生效。比如List类型的变量增加了一个元素,这个变量起始内存地址没变,但是其大小增加了,这个时候应使用第二种方法,或者重新实例化对象:
using System.Collections.Generic; using UnityEditor; public class test : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); var obj = target as PlayerControl; Undo.RecordObject(obj,"obj change"); // obj.listVal.Add(1); // 这样无法触发Undo obj.listVal = new List<int>(obj.listVal); obj.listVal.Add(1); } }
2.利用EditorUtility类中的SetDirty标记该对象已改动:
using UnityEditor; public class test : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); var obj = target as PlayerControl; obj.listVal.Add(1); EditorUtility.SetDirty(obj); } }
不知道U3D本身的撤销系统具体是否是差量保存,也不好说上面两种方式各自的好坏。
2.总结
在使用别人的东西的时候(引擎、库),多看说明文档和接口,特别是帮助相关类的接口(类名包含Helper,Tool,Utility等词汇)。