如何比较预制件和GameObject?

时间:2018-08-30 23:30:55

标签: c# unity3d

prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);

        GUI.enabled = false;
        var selection = Selection.objects.OfType<GameObject>().ToList();
        for (var i = selection.Count - 1; i >= 0; --i)
        {
            selectedObject = selection[i];
            if (prefab != null && selection.Count > 0
                && prefab != selectedObject)
                GUI.enabled = true;
        }
        if (GUILayout.Button("Replace"))
        {
            selection = Selection.objects.OfType<GameObject>().ToList();

            if (prefab != null && selection.Count > 0)
            {
                for (var i = selection.Count - 1; i >= 0; --i)
                {
                    var selected = selection[i];
                    SceneManager.SetActiveScene(SceneManager.GetSceneByName(selected.scene.name));

                    var prefabType = PrefabUtility.GetPrefabType(prefab);
                    GameObject newObject;

                    if (prefabType == PrefabType.Prefab)
                    {
                        newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
                    }
                    else
                    {
                        newObject = Instantiate(prefab);
                        newObject.name = prefab.name;
                    }

                    if (newObject == null)
                    {
                        Debug.LogError("Error instantiating prefab");
                        break;
                    }

                    Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
                    newObject.transform.parent = selected.transform.parent;
                    newObject.transform.localPosition = selected.transform.localPosition;
                    newObject.transform.localRotation = selected.transform.localRotation;
                    newObject.transform.localScale = selected.transform.localScale;
                    newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
                    Undo.DestroyObjectImmediate(selected);
                }
            }
        }

我希望仅当预制件与所选对象不同时,才启用按钮。

我第一次选择一个或多个对象,然后单击“替换”,它将用预制件替换所选对象。但是,如果我再次选择被替换的对象,它仍会启用true按钮。但是它们应该与预制件相同,而不是启用真正的按钮。

这是我要进行的比较:

prefab != selectedObject

2 个答案:

答案 0 :(得分:6)

它们是不一样的,因为在C#中使用的!=在没有重载相等运算符的两个引用类型之间使用将进行引用比较。这意味着它将检查变量是否引用相同的基础对象实例。因此,如果prefab和selectedObject是完全相同的对象实例(iirc会检查对象ID是否相等),prefab != selectedObject评估为false。

据我所知,您希望它的评估结果为false,因此,当且仅当所选对象不是预制件的副本时,才激活按钮。幸运的是,Unity3D具有一种判断是否从特定预制件实例化GameObject的方法。它称为PrefabUtility .GetCorrespondingObjectFromSource。因此,这可能符合您的要求:

更改此部分:

for (var i = selection.Count - 1; i >= 0; --i)
{
    selectedObject = selection[i];
    if (prefab != null && selection.Count > 0
        && prefab != selectedObject)
        GUI.enabled = true;
}

对此:

for (var i = selection.Count - 1; i >= 0; --i)
{
    var selectedObject = selection[i];
    if (prefab != null && selection.Count > 0
        && prefab != PrefabUtility
        .GetCorrespondingObjectFromSource(selectedObject))
        GUI.enabled = true;
}

答案 1 :(得分:0)

UnityEngine.Component类确实实现了一个工作相等的运算符(您需要使用object.Equals),并且我们可以使用反射来访问预制件和该预制件的活动实例中的所有组件。可以确定发生了什么变化,但变化不大,并且有很多棘手的情况需要处理。