自定义窗口上的Unity自定义检查器

Kla*_*e74 6 unity-game-engine

我有一个自定义窗口,显示对象列表.每个对象都有一个自定义检查器编辑器.

可以在自定义窗口中显示自定义检查器吗?

Hei*_*bug 9

您无法强制Unity3D在检查器窗口之外的其他位置绘制自定义检查器.

顺便说一句,您可以Editor使用Editor.CreateEditor方法手动设置.由于您正在显示自定义检查器,因此应该可以从内部Window.OnGUI方法手动实例化它,并使用OnInspectorGUI编辑器的公共方法在窗口内绘制编辑器.

例如,如果你连接一个叫脚本CustomScriptGameObject,并有相关的EditorCustomScriptEditor,假设你选择了GameObject从层次结构,这个代码里面可视化的自定义检查EditorWindow:

using UnityEditor;
using UnityEngine;


public class TestWindow : EditorWindow
{

    [MenuItem ("Window/Editor Window Test")]
    static void Init () 
    {
        // Get existing open window or if none, make a new one:
        TestWindow window = (TestWindow)EditorWindow.GetWindow (typeof (TestWindow));
    }

    void OnGUI () {

        GameObject sel = Selection.activeGameObject;

        CustomScript targetComp = sel.GetComponent<CustomScript>();

        if (targetComp != null)
        {
            var editor = Editor.CreateEditor(targetComp);
            editor.OnInspectorGUI();            
        }

    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

截至目前,这个问题是诸如“编辑器窗口内的 Unity 检查器”等查询的顶级谷歌结果,所以我正在制作一个 necropost 来分享我通过数小时的沮丧学到的一些非常重要的信息:

我正在构建一个编辑器工具,该工具在 EditorWindow 中使用自定义检查器,并且我使用了与 Heisenbug 完全相同的方法。有时在使用该工具时,我的控制台会被数百个神秘的空引用异常轰炸。重新启动 Unity 会使它们消失,但它们将不可避免地返回。我终于能够将问题追溯到“Editor.CreateEditor”,这是我艰难地学到的教训:

您需要手动销毁从 Editor.CreateEditor 创建的所有检查器!

通常 Unity 会在选择相关对象时实例化一个检查器,并在取消选择/删除/等对象时自动销毁该实例。但是通过 Editor.CreateEditor 创建的检查器永远不会被销毁,并且会在它正在检查的对象被销毁后很长时间内留在内存中的某个地方。

您可以通过将以下代码添加到自定义检查器来证明这一点:

void OnEnable()
{
    Debug.Log("on enable " + this.GetInstanceID());
}

void OnDisable()
{
    Debug.Log("on disable " + this.GetInstanceID());
}
Run Code Online (Sandbox Code Playgroud)

正常使用检查器,当检查器的实例被创建然后被销毁时,你总是会成对地看到这些消息。但是尝试从您的 EditorWindow 类中实例化一些检查器,您将只会看到“启用”消息。

我了解到 Unity 会在重新编译脚本时调用 OnEnable()。尝试一下,您会看到您的控制台充满了从未清理过的所有检查器实例的“启用”消息。这些实例在它们所检查的对象被销毁后仍会存在很长时间,并且 OnEnable() 中的任何初始化代码都将严重中断,引发大量神秘异常。

我的解决方案看起来像这样(此代码将在您的 EditorWindow 类中):

Editor embeddedInspector;

...

// a helper method that destroys the current inspector instance before creating a new one
// use this in place of "Editor.CreateEditor"
void RecycleInspector(Object target)
{
    if (embeddedInspector != null) DestroyImmediate(embeddedInspector);
    embeddedInspector = Editor.CreateEditor(target);
}

...

// clean up the inspector instance when the EditorWindow itself is destroyed
void OnDisable()
{
    if (embeddedInspector != null) DestroyImmediate(embeddedInspector);
}
Run Code Online (Sandbox Code Playgroud)