c# - 如何更改通过 PrefabUtility.InstantiatePrefab 实例化的 GameObject 的父对象?

标签 c# unity3d

通常您会在脚本中使用

实例化预制件的克隆
var obj = (GameObject)Instantiate(....);

然后使用

改变它的父级
var obj.transform.SetParent(...);

不过,我正在编写一个小编辑器脚本,用于在菜单项上实例化预制件,这些菜单项应保持与预制件的链接。我在 static 类中执行此操作,例如:

public static class EditorMenu
{
    // This is a reference that I already have and is not null
    privtae static Transform exampleParent;

    [MenuItem("Example/Create Clone")]
    private static void CreateClone()
    {
        var prefab = AssetDatabase.LoadAssetAtPath("Example/Path/myObject.prefab", typeof(GameObject));
        var obj = (GameObject)PrefabUtility.InstantiatePrefab(prefab);

        obj.transform.position = Vector3.zero;
        obj.transform.rotation = Quaternion.identity;

        Selection.activeGameObject = obj;
    }
}

我不得不使用

(GameObject)PrefabUtility.InstantiatePrefab(prefab);

因为 Instantiate() 没有保留到预制件的链接,而是创建了一个克隆。

到目前为止,上面的代码运行良好,对象被插入到场景中,就像我拖放它一样。

现在我想将这个新实例化的对象父对象更改为 parent 所以我添加了行

obj.transform.SetParent(exampleParent, true);

我也试过

obj.transform.parent = exampleParent;

但是两者都抛出异常:

Setting the parent of a transform which resides in a prefab is disabled to prevent data corruption. UnityEngine.Transform:SetParent(Transform)

prefab 因此 obj 是预制件的最顶层 GameObject 所以我想我设置的是整个实例化对象的父级而不是任何在预制件层次结构内部进行转换。

如何更改通过 PrefabUtility.InstantiatePrefab 实例化的 GameObject 的父级?


更新

我刚刚尝试的解决方法是实际使用 Instantiate 并执行

var obj = Object.Instantiate(prefab, cancel.transform);

// remove the added "(clone)" suffix
obj.name = prefab.name;
obj.transform.SetParent(cancel.transform);

然而,如前所述,这并不能完全保持 prefb 功能完整..所以它只允许我Revert Apply 变化。作为解决方法,它可能已经足够好了,但是因为在我的例子中,我将它用作实例化预制件的快捷方式,用户以后不应该真正更改......

最佳答案

抱歉,我刚刚发现问题:

我没有添加它,因为错误消息令人困惑/表述不当。

我正在使用 Resources.FindObjectsOfTypeAll用于检查 SomeType 类型的 exampleParent 是否在场景中。

按照 Unity 的示例,应该排除我使用的预制件

// Validation for the Menu item
[MenuItem("Example/Create Clone", true]
private bool TargetAvailable()
{
    foreach (var target in (SomeType[])Resources.FindObjectsOfTypeAll(typeof(SomeType))
    { 
        if (target.hideFlags == HideFlags.NotEditable || target.hideFlags == HideFlags.HideAndDontSave)
            continue;

        if (!EditorUtility.IsPersistent(target.transform.root.gameObject))
            continue;

        exampleParent = target.transform;
        return true;
    }

    exampleParent = null;
    return false;
}

但是这似乎实际上是错误的并且不起作用,因为它总是向我返回来自预制件的 SomeType 引用! (我已经觉得他们这样做有点奇怪

!EditorUtility.IsPersistent(target.transform.root.gameObject))
    continue;

我不确定 ! 是否是他们示例代码中的类型?!


所以听起来像不允许设置父级的错误实际上意味着并且应该说

setting the parent to a Transform which resides in a prefab is not allowed ...

我一开始就发现了实际问题。


所以再次作为解决方法,直到我弄清楚 FindObjectsOfTypeAll 的事情我切换到 Object.FindObjectOfType 而不是假设我的目标将始终在场景中处于事件状态。使用 SetParent 现在可以与 PrefabUtitlity.InstantiatePrefab 一起使用。

关于c# - 如何更改通过 PrefabUtility.InstantiatePrefab 实例化的 GameObject 的父对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54202072/

相关文章:

c# - 有什么方法可以限制 Unity3D 中面板的触摸输入吗?

c# - Windows Phone 的 Json 序列化

c# - 如何禁用 GridView 控件内的此 LinkBut​​ton?

c# - 用于多次上传的 JavaScript 问题

c# - 单击一个对象

c# - 在特定位置删除 char,从字符串末尾开始计算

xcode - Xcode 运行时崩溃

c# - 如果我在 win 7 64 位上用 C# 创建一个 dll 然后想在 WinXP 32 位上使用,会有一些不一致吗?

c# - 在页面的 Load 事件之前更新 ViewState

c# - 为什么这个添加的 UI 按钮的事件没有被调用?