- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在为 Unity3D 开发开源编辑器工具 https://github.com/JAFS6/BoxStairsTool我正在编写一个 CustomEditor。
我创建了一个主游戏对象,并将我的脚本 BoxStairs 附加到它。此脚本附加到相同的 GameObject BoxCollider。
在我的 CustomEditor 代码中,我有一个方法负责删除之前附加的两个组件以完成编辑。
这是代码:
private void FinalizeStairs ()
{
Undo.SetCurrentGroupName("Finalize stairs");
BoxStairs script = (BoxStairs)target;
GameObject go = script.gameObject;
BoxCollider bc = go.GetComponent<BoxCollider>();
if (bc != null)
{
Undo.DestroyObjectImmediate(bc);
}
Undo.DestroyObjectImmediate(target);
}
此方法在按下按钮后在 OnInspectorGUI 方法上调用
public override void OnInspectorGUI ()
{
...
if (GUILayout.Button("Finalize stairs"))
{
FinalizeStairs();
}
}
两个方法都在类上
[CustomEditor(typeof(BoxStairs))]
public sealed class BoxStairsEditor : Editor
它实际上删除了两个组件,但是,一旦删除了 BoxCollider,就会出现以下错误:
MissingReferenceException: The object of type 'BoxCollider' has been
destroyed but you are still trying to access it.
我试图通过查看跟踪来定位错误发生的位置:
Your script should either check if it is null or you should not destroy the object.
UnityEditor.Editor.IsEnabled () (at C:/buildslave/unity/build/Editor/Mono/Inspector/Editor.cs:590)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1154)
UnityEditor.InspectorWindow.DrawEditors (UnityEditor.Editor[] editors) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1030)
UnityEditor.InspectorWindow.OnGUI () (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:352)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
但是我的脚本都没有出现在上面。
我一直在查看我引用 BoxCollider 的代码,唯一的地方是创建它的地方,当创建楼梯时,一旦楼梯发生变化就会触发检查员。
在类里面:
[ExecuteInEditMode]
[SelectionBase]
public sealed class BoxStairs : MonoBehaviour
这是代码:
/*
* This method creates a disabled BoxCollider which marks the volume defined by
* StairsWidth, StairsHeight, StairsDepth.
*/
private void AddSelectionBox ()
{
BoxCollider VolumeBox = Root.GetComponent<BoxCollider>();
if (VolumeBox == null)
{
VolumeBox = Root.AddComponent<BoxCollider>();
}
if (Pivot == PivotType.Downstairs)
{
VolumeBox.center = new Vector3(0, StairsHeight * 0.5f, StairsDepth * 0.5f);
}
else
{
VolumeBox.center = new Vector3(0, -StairsHeight * 0.5f, -StairsDepth * 0.5f);
}
VolumeBox.size = new Vector3(StairsWidth, StairsHeight, StairsDepth);
VolumeBox.enabled = false;
}
我试图评论此方法的主体以允许在没有此“引用”的情况下删除 BoxCollider,但错误仍然出现,因此,我想这个方法不是问题所在。
此外,我手动删除了 BoxCollider,没有单击 Finalize 按钮来触发此代码,通过右键单击检查器“删除组件”选项上的组件,错误没有出现并且之后,点击 finalize stairs 就没有问题了。
正如@JoeBlow 在评论中提到的那样,我检查过FinalizeStairs 方法仅被调用一次。
我还检查了调用 AddSelectionBox 方法的创建过程是否在单击完成按钮时没有发生。
所以,请我帮忙解决这个问题。这是开发分支的链接https://github.com/JAFS6/BoxStairsTool/tree/feature/BoxStairsTool , 在这里你会发现上面提到的方法 FinalizeStairs 的代码只删除了 BoxStairs 脚本并且在那一刻它没有抛出任何错误。
关于此的任何想法或建议都会非常有帮助。提前致谢。
编辑:一个最小的、完整的和可验证的例子:
Assets /BoxStairs.cs
using UnityEngine;
using System.Collections.Generic;
namespace BoxStairsTool
{
[ExecuteInEditMode]
[SelectionBase]
public sealed class BoxStairs : MonoBehaviour
{
private GameObject Root;
private void Start ()
{
Root = this.gameObject;
this.AddSelectionBox();
}
private void AddSelectionBox()
{
BoxCollider VolumeBox = Root.GetComponent<BoxCollider>();
if (VolumeBox == null)
{
VolumeBox = Root.AddComponent<BoxCollider>();
}
VolumeBox.size = new Vector3(20, 20, 20);
VolumeBox.enabled = false;
}
}
}
Assets \编辑器\BoxStairsEditor.cs
using UnityEngine;
using UnityEditor;
namespace BoxStairsTool
{
[CustomEditor(typeof(BoxStairs))]
public sealed class BoxStairsEditor : Editor
{
private const string DefaultName = "BoxStairs";
[MenuItem("GameObject/3D Object/BoxStairs")]
private static void CreateBoxStairsGO ()
{
GameObject BoxStairs = new GameObject(DefaultName);
BoxStairs.AddComponent<BoxStairs>();
if (Selection.transforms.Length == 1)
{
BoxStairs.transform.SetParent(Selection.transforms[0]);
BoxStairs.transform.localPosition = new Vector3(0,0,0);
}
Selection.activeGameObject = BoxStairs;
Undo.RegisterCreatedObjectUndo(BoxStairs, "Create BoxStairs");
}
public override void OnInspectorGUI ()
{
if (GUILayout.Button("Finalize stairs"))
{
FinalizeStairs();
}
}
private void FinalizeStairs ()
{
Undo.SetCurrentGroupName("Finalize stairs");
BoxStairs script = (BoxStairs)target;
GameObject go = script.gameObject;
BoxCollider bc = go.GetComponent<BoxCollider>();
if (bc != null)
{
Undo.DestroyObjectImmediate(bc);
}
Undo.DestroyObjectImmediate(target);
}
}
}
最佳答案
我是一名程序员,所以我只是通过调试来发现问题(在我看来 :D)。
MissingReferenceException: The object of type 'BoxCollider' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
UnityEditor.Editor.IsEnabled () (at C:/buildslave/unity/build/Editor/Mono/Inspector/Editor.cs:590)
当代码尝试访问已被销毁的 Unity3D.Object 时,会发生 MissingReferenceException。
我们来看看UnityEditor.Editor.IsEnabled()
的反编译代码。
internal virtual bool IsEnabled()
{
UnityEngine.Object[] targets = this.targets;
for (int i = 0; i < targets.Length; i++)
{
UnityEngine.Object @object = targets[i];
if ((@object.hideFlags & HideFlags.NotEditable) != HideFlags.None)
{
return false;
}
if (EditorUtility.IsPersistent(@object) && !AssetDatabase.IsOpenForEdit(@object))
{
return false;
}
}
return true;
}
我们无法知 Prop 体的 590 行是哪一行。但是,我们可以知道 MissingReferenceException
在哪里发生:
// ↓↓↓↓↓↓
if ((@object.hideFlags & HideFlags.NotEditable) != HideFlags.None)
@object
是从 Editor.targets 分配的这是所有被检查对象的数组。在您的情况下,此数组中应该只有一个目标对象 - BoxCollider
组件。
总而言之,在您调用 Undo.DestroyObjectImmediate
之后,检查器无法访问目标对象(我的意思是 targets[0]
) BoxCollider
组件。
如果您深入研究检查器 (UnityEditor.InspectorWindow
) 的反编译代码,您会看到被覆盖的 OnInspectorGUI
函数被每个编辑器按顺序调用 在 UnityEditor.InspectorWindow.DrawEditors
中,包括 BoxCollider 的内部编辑器和 BoxStairs
的自定义编辑器 BoxStairsEditor
。
OnInspectorGUI
中显示的组件。BoxCollider
的编辑器/检查器 GUI。BoxCollider
移动到您的 BoxStairs
组件上方。这可能有效,但我不确定其他内部编辑器是否会访问 BoxCollider
。UnityEditorInternal.ComponentUtility.MoveComponentUp
时无效。但是,如果用户手动向上移动 BoxCollider
组件,它无需任何代码更改即可工作。采用方案一后,在Win10的Unity3D 5.4上NRE没有了。
using UnityEngine;
using UnityEditor;
namespace BoxStairsTool
{
[CustomEditor(typeof(BoxStairs))]
public sealed class BoxStairsEditor : Editor
{
private const string DefaultName = "BoxStairs";
[MenuItem("GameObject/3D Object/BoxStairs")]
private static void CreateBoxStairsGO ()
{
GameObject BoxStairs = new GameObject(DefaultName);
BoxStairs.AddComponent<BoxStairs>();
if (Selection.transforms.Length == 1)
{
BoxStairs.transform.SetParent(Selection.transforms[0]);
BoxStairs.transform.localPosition = new Vector3(0,0,0);
}
Selection.activeGameObject = BoxStairs;
Undo.RegisterCreatedObjectUndo(BoxStairs, "Create BoxStairs");
}
private void OnEnable ()
{
EditorApplication.update -= Update;
EditorApplication.update += Update;
}
public override void OnInspectorGUI ()
{
if (GUILayout.Button("Finalize stairs"))
{
needFinalize = true;
}
}
private void FinalizeStairs ()
{
Undo.SetCurrentGroupName("Finalize stairs");
BoxStairs script = (BoxStairs)target;
GameObject go = script.gameObject;
BoxCollider bc = go.GetComponent<BoxCollider>();
if (bc != null)
{
Undo.DestroyObjectImmediate(bc);
}
Undo.DestroyObjectImmediate(target);
}
bool needFinalize;
void Update()
{
if(needFinalize)
{
FinalizeStairs();
needFinalize = false;
EditorApplication.update -= Update;
}
}
}
}
关于c# - 删除 BoxCollider 时的 Unity3D MissingReferenceException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40801369/
我正在为 Unity3D 开发开源编辑器工具 https://github.com/JAFS6/BoxStairsTool我正在编写一个 CustomEditor。 我创建了一个主游戏对象,并将我的脚
我是一名优秀的程序员,十分优秀!