Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Correct way to nest a prefab inside another prefab from editor script?

Discussion in 'Prefabs' started by Pelican_7, Nov 16, 2018.

  1. Pelican_7

    Pelican_7

    Joined:
    Nov 25, 2014
    Posts:
    190
    Hi all,

    What is the correct way to nest a prefab inside another prefab from editor script?

    I have an editor script generating a couple hundred prefab variants. It's working well, however I'm looking to add a nested prefab to each of my variants.

    Currently I am creating my variants roughly like so:

    Code (CSharp):
    1. // Instantiate the base prefab.
    2. var basePrefabObject = PrefabUtility.InstantiatePrefab(myPrefabBaseAsset)
    3. ...
    4. // Create the prefab variant.
    5. var variant = PrefabUtility.SaveAsPrefabAsset(basePrefabObject, outputPath)
    6. ...
    7. // Make some variant overrides here.
    8. // This is where I would also like to add a nested prefab to the variant.
    9. ...
    10. // Record prefab variant modifications and save.
    11. PrefabUtility.RecordPrefabInstancePropertyModifications(variant);
    12. AssetDatabase.SaveAssets();
    13.  
    14. // Destroy instantiated base prefab object.
    15. DestroyImmediate(basePrefabObject);
    Thanks,
    -andy.
     
  2. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    Adding this should do the trick ;)

    gameObject = PrefabUtility.InstantiatePrefab(nested_prefab) as GameObject;
    gameObject.transform.SetParent(variant.transform);
     
  3. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
  4. Pelican_7

    Pelican_7

    Joined:
    Nov 25, 2014
    Posts:
    190
    Awesome, thanks so much. I've got it working now. I was actually trying to set the transform's parent like this already but was getting the error:

    "Setting the parent of a transform which resides in a Prefab is disabled to prevent data corruption."

    I still get this issue when using the NestBInAViaInstances approach (perhaps I need to save the prefab first?) but using the NestBInAViaContent approach after I have first saved my variant instance works exactly as I need.

    Thanks a lot!
    -andy.
     
    MatthieuPr likes this.
  5. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    @Pelican_7
    Can you share a test project with your script?
     
  6. Pelican_7

    Pelican_7

    Joined:
    Nov 25, 2014
    Posts:
    190
    Sure, I have created a quick demo project here - https://drive.google.com/file/d/1LVp6ORKejs56R9fPVebjOFmaG9IodxlZ/view?usp=sharing.

    If you use the context menu of the PrefabExample script in the scene, there are two methods "NestPrefabAfterSavingAsset (No Issues)" and "NestPrefabBeforeSavingAsset (Error)". The latter shows the error that occurs when trying to nest a prefab before it is saved. I included the working method too, where I just nest the prefab after saving, just in case.

    Here is the full script in the demo project:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class PrefabExample : MonoBehaviour
    5. {
    6.     public GameObject basePrefab;
    7.     public string outputPath;
    8.     public GameObject prefabToNest;
    9.  
    10.     [ContextMenu("NestPrefabAfterSavingAsset (No Issues)")]
    11.     public void NestPrefabAfterSavingAsset()
    12.     {
    13.         // Load base prefab.
    14.         string basePrefabPath = AssetDatabase.GetAssetPath(basePrefab);
    15.         Object basePrefabAsset = AssetDatabase.LoadAssetAtPath<Object>(basePrefabPath);
    16.         GameObject basePrefabObject = (GameObject)PrefabUtility.InstantiatePrefab(basePrefabAsset);
    17.  
    18.         // Create prefab variant.
    19.         GameObject prefabVariant = PrefabUtility.SaveAsPrefabAsset(basePrefabObject, outputPath);
    20.  
    21.         // I set some overrides specific to the variant here (removed).
    22.  
    23.         // Record modifications and save.
    24.         PrefabUtility.RecordPrefabInstancePropertyModifications(prefabVariant);
    25.         AssetDatabase.SaveAssets();
    26.  
    27.         // Clean up.
    28.         DestroyImmediate(basePrefabObject);
    29.  
    30.         // Load the previously created prefab variant and nest the prefab.
    31.         var prefabVariantContents = (GameObject)PrefabUtility.LoadPrefabContents(outputPath);
    32.  
    33.         // Nest the prefab.
    34.         var prefabToNestObject = (GameObject)PrefabUtility.InstantiatePrefab(prefabToNest);
    35.         prefabToNestObject.transform.SetParent(prefabVariantContents.transform);
    36.         PrefabUtility.SaveAsPrefabAsset(prefabVariantContents, outputPath);
    37.  
    38.         // Clean up.
    39.         PrefabUtility.UnloadPrefabContents(prefabVariantContents);
    40.     }
    41.  
    42.     [ContextMenu("NestPrefabBeforeSavingAsset (Error)")]
    43.     public void NestPrefabBeforeSavingAsset()
    44.     {
    45.         // Load base prefab.
    46.         string basePrefabPath = AssetDatabase.GetAssetPath(basePrefab);
    47.         Object basePrefabAsset = AssetDatabase.LoadAssetAtPath<Object>(basePrefabPath);
    48.         GameObject basePrefabObject = (GameObject)PrefabUtility.InstantiatePrefab(basePrefabAsset);
    49.  
    50.         // Create prefab variant.
    51.         GameObject prefabVariant = PrefabUtility.SaveAsPrefabAsset(basePrefabObject, outputPath);
    52.  
    53.         // I set some overrides specific to the variant here (removed).
    54.  
    55.         // Nest the prefab.
    56.         var prefabToNestObject = (GameObject)PrefabUtility.InstantiatePrefab(prefabToNest);
    57.         prefabToNestObject.transform.SetParent(prefabVariant.transform); // Generates error message.
    58.  
    59.         // Record modifications and save.
    60.         PrefabUtility.RecordPrefabInstancePropertyModifications(prefabVariant);
    61.         AssetDatabase.SaveAssets();
    62.  
    63.         // Clean up.
    64.         DestroyImmediate(basePrefabObject);
    65.     }
    66. }
    67.  
    -andy.