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等词汇)。

原文地址:https://www.cnblogs.com/yaoh/p/5204273.html