Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change the parent of a GameObject instantiated via PrefabUtility.InstantiatePrefab?

Usually you would instantiate a clone of a prefab in a script using

var obj = (GameObject)Instantiate(....);

and than change it's parent using

var obj.transform.SetParent(...);

However I'm writing on a little editor script for instantiating prefabs over the menu entries that should keep their link to the prefab. I do it in a static class like:

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;
    }
}

I had to use

(GameObject)PrefabUtility.InstantiatePrefab(prefab);

because Instantiate() doesn't keep the link to the prefab but creates a clone.

So the above code works great so far and the object is inserted to the scene as if I would drag and drop it.

Now I would like to change this newly instantiated objects parent to parent so I added the line

obj.transform.SetParent(exampleParent, true);

I also tried

obj.transform.parent = exampleParent;

But both throw an exception:

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

prefab and thereby obj are the topmost GameObject of the prefab so I thought I am setting the parent of the whole instantiated object not any transform inside of the prefab hierachy.

How can I change the parent of a GameObject instantiated via PrefabUtility.InstantiatePrefab?


Update

A workarround I just tried was to actually use Instantiate and do

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

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

however as mentioned before this doesn't completely keep the prefb functionality intact .. so it only allows me to Revert but not to Apply changes. As workaround it might be good enough however since in my case I use it as a shortcut for instantiating a prefab which users are not really supposed to change later...

like image 590
derHugo Avatar asked Jan 31 '26 18:01

derHugo


1 Answers

Sorry I just found the issue:

I didn't add it since the error message was confusing/bad formulated.

I was using Resources.FindObjectsOfTypeAll for checking if the exampleParent of type SomeType was in the scene.

Following Unity's example which should exclude prefabs I used

// 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;
}

But this seems actually to be wrong and not working since it allways returned me the SomeType reference from the prefabs! (I already found it a bit strange that they do

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

I'm not sure if that ! maybe is a type in their example code?!


So the error which sounds like setting the parent was not allowed actually means and should say

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

than I would have found the actual issue in the first place.


So again as a workaround until I can figure out that FindObjectsOfTypeAll thing I switched to Object.FindObjectOfType instead assuming my target will always be active in the scene. And using SetParent works now together with PrefabUtitlity.InstantiatePrefab.

like image 145
derHugo Avatar answered Feb 02 '26 08:02

derHugo