1

我有一个非常复杂的 Unity 编辑器脚本来修改模型。通过在资产文件夹中创建一个新对象,然后在其检查器中为其提供模型、一些修改器并按下应用来使用它。这会修改模型并将创建的对象替换为新的对象预制件。

当按下应用时,该方法Apply()被调用,然后运行,控制台打印出:

调用的目标已引发异常。System.Reflection.MonoMethod.Invoke(System.Object obj,BindingFlags invokeAttr,System.Reflection.Binder binder,System.Object[] 参数,System.Globalization.CultureInfo 文化)(在 /Users/builduser/buildslave/mono/build/ mcs/class/corlib/System.Reflection/MonoMethod.cs:232) System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] 参数) (在 /Users/builduser/buildslave/mono/build/mcs /class/corlib/System.Reflection/MethodBase.cs:115) UnityEditor.HostView.Invoke (System.String methodName, System.Object obj) (在 C:/buildslave/unity/build/Editor/Mono/HostView.cs: 272) UnityEditor.HostView.Invoke (System.String methodName) (在 C:/buildslave/unity/build/Editor/Mono/HostView.cs:265) UnityEditor.HostView.InvokeOnGUI (Rect onGUIPosition) (在 C:

我发现了一个 2014 年的问题,有一个类似的错误,但情况不同,这里没有答案。

我检查了MattRix 的反编译 Unity 存储库以了解可能导致异常的原因,即使该存储库的版本为 2017.1.0f3 并且我使用的是 2017.1.1f1,我想我找到了问题发生的地方。在DrawPreviewsAndLabels()

IPreviewable[] editorsWithPreviews = this.GetEditorsWithPreviews(this.tracker.activeEditors);

接着

GetEditorsWithPreviews(Editor[] editors){
...
for (int i = 0; i < editors.Length; i++)
            {
                Editor editor = editors[i];
...

好像调用异常就行了Editor editor = editors[i];。这让我觉得这this.tracker.activeEditors是一个包含null. 这就是我坚持的地方。

什么可能导致这种情况,我可以做些什么或检查来修复这个错误?

编辑:有人提出这可能意味着它this.tracker.activeEditors本身是空的。如果是这种情况,我认为异常会发生在editors.Length并且或至少它不应该进入 for 循环。由于行号可能随着 Unity 版本的变化而变化,该代码中的行实际上可能不是异常的原因,但我无法知道这一点。

我不能轻易修复这个空指针的问题是它发生在编辑器代码中,没有来自我的代码的任何调用,而且我不知道该怎么做,this.tracker.activeEditors或者导致它的任何原因将被正确分配到它应该在的位置。

我是否必须制作一些可能不活跃的东西,以便有活跃的编辑器,不管这意味着什么?

这是我的Apply()方法:

private void Apply(List<Mesh> meshes, List<Material[]> materials, Chamferer chamferer)
{
    GameObject newObject = Instantiate(chamferer.gameObject);
    Object targetPrefab = PrefabUtility.GetPrefabObject(chamferer);

    string name = chamferer.source.name;
    //Delete previous meshes
    MeshFilter[] filters = newObject.transform.GetComponentsInChildren<MeshFilter>();
    for (int i = 0; i < filters.Length; i++)
    {
        filters[i].transform.SetParent(null);
        GameObject.DestroyImmediate(filters[i].gameObject);
    }

    string prefabPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(targetPrefab));

    Mesh prev = null;
    //Add new meshes
    for (int i = 0; i < meshes.Count; i++)
    {
        Mesh mesh = meshes[i];
        Mesh newMesh = EdgeChamfer.AddChamfer(mesh, chamferer.scale);
        GameObject obj = new GameObject(mesh.name);
        obj.transform.SetParent(newObject.transform);
        MeshFilter mf = obj.AddComponent<MeshFilter>();
        MeshRenderer mr = obj.AddComponent<MeshRenderer>();
        mf.sharedMesh = newMesh;
        mr.sharedMaterials = materials[i];

        //Adds mesh under prefab
        if (i == 0)
        {
            AssetDatabase.CreateAsset(newMesh, prefabPath + "/" + name + ".asset");
            prev = newMesh;
        }
        else
        {
            AssetDatabase.AddObjectToAsset(newMesh, prev);
            prev = newMesh;
        }
    }
    AssetDatabase.SaveAssets();

    GameObject newPrefab = PrefabUtility.ReplacePrefab(newObject, targetPrefab);

    //Renames the object accordingly
    string renamingerr = AssetDatabase.RenameAsset(prefabPath + "/" + newPrefab.name + ".prefab", "Chamfered" + name);
    if (renamingerr != "")
    {
        Debug.Log(renamingerr);
    }
    Selection.activeObject = newPrefab;
    EditorGUIUtility.PingObject(newPrefab);
    GameObject.DestroyImmediate(newObject);
}

并完整GetEditorsWithPreviews()来自MattRix 的回购

public IPreviewable[] GetEditorsWithPreviews(Editor[] editors)
        {
            IList<IPreviewable> list = new List<IPreviewable>();
            int num = -1;
            for (int i = 0; i < editors.Length; i++)
            {
                Editor editor = editors[i];
                num++;
                if (!(editor.target == null))
                {
                    if (!EditorUtility.IsPersistent(editor.target) || !(AssetDatabase.GetAssetPath(editor.target) != AssetDatabase.GetAssetPath(editors[0].target)))
                    {
                        if (EditorUtility.IsPersistent(editors[0].target) || !EditorUtility.IsPersistent(editor.target))
                        {
                            if (!this.ShouldCullEditor(editors, num))
                            {
                                if (!(editors[0] is AssetImporterEditor) || editor is AssetImporterEditor)
                                {
                                    if (editor.HasPreviewGUI())
                                    {
                                        list.Add(editor);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            foreach (IPreviewable current in this.m_Previews)
            {
                if (current.HasPreviewGUI())
                {
                    list.Add(current);
                }
            }
            return list.ToArray<IPreviewable>();
        }
4

1 回答 1

0

OnInspectorGUI()似乎在替换对象后尝试执行某些操作时可能会出现错误。

如果不是替换预制件,而是创建一个新的预制件,则不会出现该错误。所以在代码中,问题是通过替换来解决的

GameObject newPrefab = PrefabUtility.ReplacePrefab(newObject, targetPrefab);

在“应用()”中

    GameObject newPrefab = PrefabUtility.CreatePrefab(prefabPath + "/" + name + ".prefab", newObject);
于 2017-12-21T23:02:31.500 回答