Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Replace game object with prefab?

Discussion in 'Editor & General Support' started by DaveA, Jun 4, 2009.

  1. stdiopt

    stdiopt

    Joined:
    Feb 1, 2015
    Posts:
    3
    Does this script maintain the order in hierarchy?, Lets say in a RectTransform i want to replace all backgrounds with some prefab instance, I did something already but, the issue is when adding Prefab, it becomes last child keeping the background "rect transform" on top of every other elements (I guess hierarchy order matter in RectTransforms),

    Is there a easy way to replace a gameObject maintaining hierarchy order?
     
  2. VesuvianPrime

    VesuvianPrime

    Joined:
    Feb 26, 2013
    Posts:
    135
  3. noctvm

    noctvm

    Joined:
    Dec 19, 2015
    Posts:
    1
    Hi guys, I have a problem hen I drag the script, a windows said that I can't add the script because need to derivate from monobehaviour, do you know why?

    cheers.
     
  4. Carolinetis

    Carolinetis

    Joined:
    Feb 20, 2016
    Posts:
    13
    Hi everyone! I'm new using Unity and found your script very useful and necessary, but I have a question... where should I place it to use it? I know it's a very basic question, I'm sorry. I'd appreciate any help.

    Thanks again!
     
  5. Mark-Davis

    Mark-Davis

    Joined:
    Jun 21, 2011
    Posts:
    156
    Huge thanks to everyone who worked on this! I was able to replace these books in a few seconds. Awesome!
    MoreBooks.jpg
     
  6. Arno1975

    Arno1975

    Joined:
    Aug 14, 2013
    Posts:
    43
    I'm getting an error

     
  7. ethos42

    ethos42

    Joined:
    Dec 20, 2016
    Posts:
    1
    This did exactly what I needed for my situation. Thanks!
     
  8. muzboz

    muzboz

    Joined:
    Aug 8, 2012
    Posts:
    108
    FYI, for anyone just coming to this thread and looking for the best version, I found "fermmmm"s version the best that I tried.

    I tried "VesuvianPrime"'s but it wouldn't compile because it needed other "Hydra" code.

    So I went back further and tried "Elzean"'s version, but I kept mucking it up, and having swizzly problems with it, and having objects deleted.

    So I went back to "fermmmm"s nice simple one adn it worked first go, nice and straight forward!

    I didn't try any further back.

    Thanks all, very handy!
     
  9. kapyar

    kapyar

    Joined:
    Dec 13, 2014
    Posts:
    8
    My version of this script
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. public class ReplaceGameObjects : ScriptableWizard
    6. {
    7.     [System.Serializable]
    8.     public class Rule
    9.     {
    10.         public string Key;
    11.         public GameObject Value;
    12.     }
    13.  
    14.     public bool IsDeleteOld;
    15.     public bool IsCreateNewRoot;
    16.  
    17.     [Tooltip("If no prefix will use New_<Root.name>")]
    18.     public string CustomPrefix;
    19.  
    20.     public GameObject Root;
    21.  
    22.     public List<Rule> toReplace;
    23.  
    24.     private List<GameObject> toDelete = new List<GameObject>();
    25.  
    26.     private const string PREFIX = "New_";
    27.  
    28.     [MenuItem("Area730/Replace GameObjects")]
    29.     static void CreateWizard()
    30.     {
    31.         Debug.Log("[ReplaceGameObjects] CreateWizard");
    32.         ScriptableWizard wiz = DisplayWizard("Replace GameObjects", typeof(ReplaceGameObjects), "Close", "Replace");
    33.     }
    34.  
    35.     void OnWizardCreate()
    36.     {
    37.  
    38.     }
    39.  
    40.     void OnWizardOtherButton()
    41.     {
    42.         Debug.Log("[ReplaceGameObjects] OnWizardCreate");
    43.  
    44.         if (string.IsNullOrEmpty(CustomPrefix))
    45.         {
    46.             CustomPrefix = PREFIX;
    47.         }
    48.  
    49.         ChangeInSelectedRoot();
    50.  
    51.         ShowNotification("Job is done");
    52.     }
    53.  
    54.     void OnWizardUpdate()
    55.     {
    56.         if (Root == null)
    57.         {
    58.             errorString = "Assign the root object!";
    59.             isValid = false;
    60.         }
    61.         else
    62.         {
    63.             errorString = "";
    64.             isValid = true;
    65.         }
    66.  
    67.         helpString = "Replace objects that has same NAME with one Prefab";
    68.     }
    69.  
    70.  
    71.     private void ChangeInSelectedRoot()
    72.     {
    73.         var goChild = Root.GetComponentInChildren<Transform>();
    74.  
    75.         GameObject currentRoot;
    76.         if (IsCreateNewRoot)
    77.         {
    78.             var newRoot = GameObject.Find(CustomPrefix + Root.name);
    79.  
    80.             if (newRoot == null)
    81.             {
    82.                 newRoot  = new GameObject(CustomPrefix + Root.name);
    83.  
    84.                 newRoot.transform.position = Root.transform.position;
    85.                 newRoot.transform.rotation = Root.transform.rotation;
    86. //                newRoot.transform.lossyScale = Root.transform.lossyScale;
    87.  
    88.                 newRoot.isStatic = Root.isStatic;
    89.             }
    90.             currentRoot = newRoot;
    91.         }
    92.         else
    93.         {
    94.             currentRoot = Root;
    95.         }
    96.  
    97.         if (goChild != null)
    98.         {
    99.             foreach (Transform child in goChild)
    100.             {
    101.                 foreach (var replace in toReplace)
    102.                 {
    103.                     string nameKey = replace.Key;
    104.  
    105.                     if (nameKey == child.name)
    106.                     {
    107.                         GameObject newObject;
    108.                         newObject = (GameObject) EditorUtility.InstantiatePrefab(replace.Value);
    109.  
    110.                         if (child.transform.parent.name == Root.name)
    111.                         {
    112.                             newObject.transform.parent = currentRoot.transform;
    113.                         }
    114.                         else
    115.                         {
    116.                             newObject.transform.parent = child.transform.parent;
    117.                         }
    118.  
    119.                         newObject.transform.localPosition = child.transform.localPosition;
    120.                         newObject.transform.localRotation = child.transform.localRotation;
    121.                         newObject.transform.localScale    = child.transform.localScale;
    122.  
    123. //                        Debug.Log(string.Format("[ReplaceGameObjects] {0} in {1}", child.transform.localPosition, newObject.transform.localPosition));
    124.                         toDelete.Add(child.gameObject);
    125.                     }
    126.                 }
    127.             }
    128.         }
    129.  
    130.         if (IsDeleteOld)
    131.         {
    132.             foreach (var del in toDelete)
    133.             {
    134.                 DestroyImmediate(del);
    135.             }
    136.         }
    137.     }
    138.  
    139.  
    140.     private void ShowNotification(string msg)
    141.     {
    142.         EditorUtility.DisplayDialog(msg, "", "Ok");
    143.     }
    144. }
    145.  
    146.  
     
  10. NSwat

    NSwat

    Joined:
    Apr 22, 2017
    Posts:
    6
    This is a amazing, must have script.
    thx
     
  11. _creatio_

    _creatio_

    Joined:
    Mar 21, 2013
    Posts:
    43
    Midfied @Elzean 's version to make it work with Unity 5.6.1 No other changes.
    Thank you guys for such a usefull tool!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections.Generic;
    4. // CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
    5. // March 2010
    6. //Modified by Kristian Helle Jespersen
    7. //June 2011
    8. //Modified by Connor Cadellin McKee for Excamedia
    9. //April 2015
    10. //Modified by Fernando Medina (fermmmm)
    11. //April 2015
    12. //Modified by Julien Tonsuso (www.julientonsuso.com)
    13. //July 2015
    14. //Changed into editor window and added instant preview in scene view
    15. //Modified by Alex Dovgodko
    16. //June 2017
    17. //Made changes to make things work with Unity 5.6.1
    18. public class ReplaceWithPrefab : EditorWindow
    19. {
    20.     public GameObject Prefab;
    21.     public GameObject[] ObjectsToReplace;
    22.     public List<GameObject> TempObjects = new List<GameObject>();
    23.     public bool KeepOriginalNames = true;
    24.     public bool EditMode = false;
    25.     // Add menu named "My Window" to the Window menu
    26.     [MenuItem("Window/ReplaceWithPrefab")]
    27.     static void Init()
    28.     {
    29.         // Get existing open window or if none, make a new one:
    30.         ReplaceWithPrefab window = (ReplaceWithPrefab)EditorWindow.GetWindow(typeof(ReplaceWithPrefab));
    31.         window.Show();
    32.     }
    33.     void OnSelectionChange()
    34.     {
    35.         GetSelection();
    36.         Repaint();
    37.     }
    38.     void OnGUI()
    39.     {
    40.         EditMode = GUILayout.Toggle(EditMode, "Edit");
    41.         if (GUI.changed)
    42.         {
    43.             if(EditMode)
    44.                 GetSelection();
    45.             else
    46.                 ResetPreview();
    47.         }
    48.         KeepOriginalNames = GUILayout.Toggle(KeepOriginalNames, "Keep names");
    49.         GUILayout.Space(5);
    50.         if (EditMode)
    51.         {
    52.             ResetPreview();
    53.          
    54.             GUI.color = Color.yellow;
    55.             if (Prefab != null)
    56.             {
    57.                 GUILayout.Label("Prefab: ");
    58.                 GUILayout.Label(Prefab.name);
    59.             }else{
    60.                 GUILayout.Label("No prefab selected");
    61.             }
    62.             GUI.color = Color.white;
    63.          
    64.             GUILayout.Space(5);
    65.             GUILayout.BeginScrollView(new Vector2());
    66.             foreach (GameObject go in ObjectsToReplace)
    67.             {
    68.                 GUILayout.Label(go.name);
    69.                 if (Prefab != null)
    70.                 {
    71.                     GameObject newObject;
    72.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(Prefab);
    73.                     newObject.transform.SetParent(go.transform.parent, true);
    74.                     newObject.transform.localPosition = go.transform.localPosition;
    75.                     newObject.transform.localRotation = go.transform.localRotation;
    76.                     newObject.transform.localScale = go.transform.localScale;
    77.                     TempObjects.Add(newObject);
    78.                     if (KeepOriginalNames)
    79.                         newObject.transform.name = go.transform.name;
    80.                     go.SetActive(false);
    81.                 }
    82.             }
    83.             GUILayout.EndScrollView();
    84.             GUILayout.Space(5);
    85.             GUILayout.BeginHorizontal();
    86.             if(GUILayout.Button("Apply"))
    87.             {
    88.                 foreach (GameObject go in ObjectsToReplace)
    89.                 {
    90.                     DestroyImmediate(go);
    91.                 }
    92.                 EditMode = false;
    93.             };
    94.             if (GUILayout.Button("Cancel"))
    95.             {
    96.                 ResetPreview();
    97.                 EditMode = false;
    98.             };
    99.             GUILayout.EndHorizontal();
    100.         }
    101.         else
    102.         {
    103.             ObjectsToReplace = new GameObject[0];
    104.             TempObjects.Clear();
    105.             Prefab = null;
    106.         }
    107.      
    108.     }
    109.     void OnDestroy()
    110.     {
    111.         ResetPreview();
    112.     }
    113.     void GetSelection()
    114.     {
    115.         if (EditMode && Selection.activeGameObject != null)
    116.         {
    117.             PrefabType t = PrefabUtility.GetPrefabType(Selection.activeGameObject);
    118.             if (t == PrefabType.Prefab) //Here goes the fix
    119.             {
    120.                 Prefab = Selection.activeGameObject;
    121.             }
    122.             else
    123.             {
    124.                 ResetPreview();
    125.                 ObjectsToReplace = Selection.gameObjects;
    126.             }
    127.         }
    128.     }
    129.     void ResetPreview()
    130.     {
    131.         if (TempObjects != null)
    132.         {
    133.             foreach (GameObject go in TempObjects)
    134.             {
    135.                 DestroyImmediate(go);
    136.             }
    137.         }
    138.         foreach (GameObject go in ObjectsToReplace)
    139.         {
    140.             go.SetActive(true);
    141.         }
    142.         TempObjects.Clear();
    143.     }
    144. }
     
    nirvanajie and Elzean like this.
  12. seyacat

    seyacat

    Joined:
    Sep 10, 2015
    Posts:
    23
    Ty so much, you save my day, replace based on selection its the better choice.
    EDITED:
    I need to replace and save scene

    EditorApplication.MarkSceneDirty ();

    makes the magic.
     
    Last edited: Sep 28, 2017
  13. xelanoimis

    xelanoimis

    Joined:
    Oct 29, 2013
    Posts:
    39
    Thank you all for this. Time to share my version (no menu but shortcuts). It works like this:

    1. select some objects in scene view or scene hierarchy (hold ctrl key for multiple objects)
    2. select one prefab in project window or one more object in scene view
    3. Ctrl+Shift+R to replace all other objects with the last one (active selection)
    or
    Ctrl+Shift+D to clone the last one at each of selected objects positions (don't delete destinations)

    Works with normal instance (not prefab instance) as reference so it's easy to use it directly in the scene view to replace or duplicate objects.

    Also it supports undo and it keeps the nice order in the hierarchy.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections.Generic;
    4. using UnityEditor.SceneManagement;
    5.  
    6. public class GFTools
    7. {
    8.     // hot keys: _ normal, # ctrl, % shift, & alt
    9.  
    10.     [MenuItem("Tools/GF/Duplicate with prefab #%D")]
    11.     private static void DuplicateWithPrefab()
    12.     {
    13.         InstantiateWithPrefab(false);
    14.     }
    15.  
    16.     [MenuItem("Tools/GF/Replace with prefab #%R")]
    17.     private static void ReplaceWithPrefab()
    18.     {
    19.         InstantiateWithPrefab(true);
    20.     }
    21.  
    22.     private static void InstantiateWithPrefab(bool deleteDestination)
    23.     {
    24.         GameObject originalObject = null;
    25.         Object[] prefabList = Selection.GetFiltered(typeof(UnityEngine.GameObject), SelectionMode.Assets);
    26.  
    27.         // try to find a prefab
    28.         foreach (var o in prefabList)
    29.         {
    30.             PrefabType t = PrefabUtility.GetPrefabType(o);
    31.             if (t == PrefabType.Prefab || t == PrefabType.ModelPrefab)
    32.             {
    33.                 if (originalObject == null)
    34.                 {
    35.                     originalObject = o as GameObject;
    36.                 }
    37.                 else
    38.                 {
    39.                     Debug.Log("select only one prefab in project window");
    40.                     return;
    41.                 }
    42.             }
    43.         }
    44.  
    45.         // if no prefab found, use active object
    46.         if (originalObject == null)
    47.         {
    48.             originalObject = Selection.activeGameObject;
    49.         }
    50.  
    51.         if (originalObject == null)
    52.         {
    53.             Debug.Log("select one prefab in project window or an object in the scene window");
    54.             return;
    55.         }
    56.  
    57.         // clear selection
    58.         Selection.objects = new Object[0];
    59.  
    60.         if (deleteDestination)
    61.             Debug.Log("Replacing with " + originalObject.name + ":");
    62.         else
    63.             Debug.Log("Duplicating " + originalObject.name + " at:");
    64.  
    65.         List<GameObject> newObjects = new List<GameObject>();
    66.  
    67.         for (int i=0; i<prefabList.Length; i++)
    68.         {
    69.             GameObject go = prefabList[i] as GameObject;
    70.             if (!go || go == originalObject)
    71.                 continue;
    72.  
    73.             PrefabType t = PrefabUtility.GetPrefabType(go);
    74.             if (t != PrefabType.Prefab && t != PrefabType.ModelPrefab)
    75.             {
    76.                 Debug.Log("  " + (newObjects.Count + 1).ToString() + " " + go.name);
    77.  
    78.                 GameObject newObject;
    79.  
    80.                 newObject = (GameObject)PrefabUtility.InstantiatePrefab(originalObject);
    81.                 if(newObject == null)
    82.                 {
    83.                     newObject = GameObject.Instantiate(originalObject);
    84.                     if (newObject == null)
    85.                     {
    86.                         Debug.Log("failed to instantiate");
    87.                         break;
    88.                     }
    89.                 }
    90.  
    91.                 Undo.RegisterCreatedObjectUndo(newObject, "created prefab");
    92.                 newObject.name = originalObject.name;
    93.  
    94.                 newObject.transform.SetParent(go.transform.parent, true);
    95.                 newObject.transform.localPosition = go.transform.localPosition;
    96.                 newObject.transform.localRotation = go.transform.localRotation;
    97.                 newObject.transform.localScale = go.transform.localScale;
    98.                 newObject.transform.SetSiblingIndex(go.transform.GetSiblingIndex()+1);
    99.  
    100.                 newObjects.Add(newObject);
    101.  
    102.                 if (deleteDestination)
    103.                     Undo.DestroyObjectImmediate(go);
    104.             }
    105.         }
    106.  
    107.         Selection.objects = newObjects.ToArray();
    108.  
    109.         EditorSceneManager.MarkAllScenesDirty();
    110.     }
    111. }
     
    leni8ec, ChaosWWW and ZiadJ like this.
  14. Macabana

    Macabana

    Joined:
    Oct 17, 2013
    Posts:
    3
    I really appreciate all that folk that have add a line in this incredible script that save hours of work, I can't believe how this handy tool is not part of Unity regular tools
     
  15. Feelnside

    Feelnside

    Joined:
    Sep 30, 2016
    Posts:
    83
    Thanks to everyone who was took a part in the script development. That script saved so much time of work!
     
  16. Hypertectonic

    Hypertectonic

    Joined:
    Dec 16, 2016
    Posts:
    75
    This is an update from @_creatio_ and @Elzean 's version, with an extra set of booleans to chose if scale and rotation should be applied to the prefab instances or ignored. Also added @seyacat 's suggestion.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditor.SceneManagement;
    4. using System.Collections.Generic;
    5.  
    6. // COMMUNITY THREAD LINK https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    7. // CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
    8. // March 2010
    9. //Modified by Kristian Helle Jespersen
    10. //June 2011
    11. //Modified by Connor Cadellin McKee for Excamedia
    12. //April 2015
    13. //Modified by Fernando Medina (fermmmm)
    14. //April 2015
    15. //Modified by Julien Tonsuso (www.julientonsuso.com)
    16. //July 2015
    17. //Changed into editor window and added instant preview in scene view
    18. //Modified by Alex Dovgodko
    19. //June 2017
    20. //Made changes to make things work with Unity 5.6.1
    21. //March 2018
    22. //Added link to community thread, booleans to chose if scale and rotation are applied, mark scene as dirty, changed menu item to tools. By Hyper
    23.  
    24. public class ReplaceWithPrefab : EditorWindow
    25. {
    26.     public GameObject Prefab;
    27.     public GameObject[] ObjectsToReplace;
    28.     public List<GameObject> TempObjects = new List<GameObject>();
    29.     public bool KeepOriginalNames = true;
    30.     public bool EditMode = false;
    31.     public bool ApplyRotation = true;
    32.     public bool ApplyScale = true;
    33.     // Add menu named "My Window" to the Window menu
    34.     [MenuItem("Tools/ReplaceWithPrefab")]
    35.     static void Init()
    36.     {
    37.         // Get existing open window or if none, make a new one:
    38.         ReplaceWithPrefab window = (ReplaceWithPrefab)EditorWindow.GetWindow(typeof(ReplaceWithPrefab));
    39.         window.Show();
    40.     }
    41.     void OnSelectionChange()
    42.     {
    43.         GetSelection();
    44.         Repaint();
    45.     }
    46.     void OnGUI()
    47.     {
    48.         EditMode = GUILayout.Toggle(EditMode, "Edit");
    49.         if (GUI.changed)
    50.         {
    51.             if (EditMode)
    52.                 GetSelection();
    53.             else
    54.                 ResetPreview();
    55.         }
    56.         KeepOriginalNames = GUILayout.Toggle(KeepOriginalNames, "Keep names");
    57.         ApplyRotation = GUILayout.Toggle(ApplyRotation, "Apply rotation");
    58.         ApplyScale = GUILayout.Toggle(ApplyScale, "Apply scale");
    59.         GUILayout.Space(5);
    60.         if (EditMode)
    61.         {
    62.             ResetPreview();
    63.  
    64.             GUI.color = Color.yellow;
    65.             if (Prefab != null)
    66.             {
    67.                 GUILayout.Label("Prefab: ");
    68.                 GUILayout.Label(Prefab.name);
    69.             }
    70.             else
    71.             {
    72.                 GUILayout.Label("No prefab selected");
    73.             }
    74.             GUI.color = Color.white;
    75.  
    76.             GUILayout.Space(5);
    77.             GUILayout.BeginScrollView(new Vector2());
    78.             foreach (GameObject go in ObjectsToReplace)
    79.             {
    80.                 GUILayout.Label(go.name);
    81.                 if (Prefab != null)
    82.                 {
    83.                     GameObject newObject;
    84.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(Prefab);
    85.                     newObject.transform.SetParent(go.transform.parent, true);
    86.                     newObject.transform.localPosition = go.transform.localPosition;
    87.                     if (ApplyRotation)
    88.                     {
    89.                         newObject.transform.localRotation = go.transform.localRotation;
    90.                     }
    91.                     if (ApplyScale)
    92.                     {
    93.                         newObject.transform.localScale = go.transform.localScale;
    94.                     }
    95.                     TempObjects.Add(newObject);
    96.                     if (KeepOriginalNames)
    97.                         newObject.transform.name = go.transform.name;
    98.                     go.SetActive(false);
    99.                 }
    100.             }
    101.             GUILayout.EndScrollView();
    102.             GUILayout.Space(5);
    103.             GUILayout.BeginHorizontal();
    104.             if (GUILayout.Button("Apply"))
    105.             {
    106.                 foreach (GameObject go in ObjectsToReplace)
    107.                 {
    108.                     DestroyImmediate(go);
    109.                 }
    110.                 EditMode = false;
    111.                 EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // So that we don't forget to save...
    112.             };
    113.             if (GUILayout.Button("Cancel"))
    114.             {
    115.                 ResetPreview();
    116.                 EditMode = false;
    117.             };
    118.             GUILayout.EndHorizontal();
    119.         }
    120.         else
    121.         {
    122.             ObjectsToReplace = new GameObject[0];
    123.             TempObjects.Clear();
    124.             Prefab = null;
    125.         }
    126.  
    127.     }
    128.     void OnDestroy()
    129.     {
    130.         ResetPreview();
    131.     }
    132.     void GetSelection()
    133.     {
    134.         if (EditMode && Selection.activeGameObject != null)
    135.         {
    136.             PrefabType t = PrefabUtility.GetPrefabType(Selection.activeGameObject);
    137.             if (t == PrefabType.Prefab) //Here goes the fix
    138.             {
    139.                 Prefab = Selection.activeGameObject;
    140.             }
    141.             else
    142.             {
    143.                 ResetPreview();
    144.                 ObjectsToReplace = Selection.gameObjects;
    145.             }
    146.         }
    147.     }
    148.     void ResetPreview()
    149.     {
    150.         if (TempObjects != null)
    151.         {
    152.             foreach (GameObject go in TempObjects)
    153.             {
    154.                 DestroyImmediate(go);
    155.             }
    156.         }
    157.         foreach (GameObject go in ObjectsToReplace)
    158.         {
    159.             go.SetActive(true);
    160.         }
    161.         TempObjects.Clear();
    162.     }
    163. }
     
    _creatio_ likes this.
  17. Arno1975

    Arno1975

    Joined:
    Aug 14, 2013
    Posts:
    43
    There is this posibility to add a sjon file, does anybody know what that does..

    my wish is to have a sjon file like,

    Generic model <716520 floor 1000x2431> , 716520 prefab floor 1000x2431

    So in my project look for all elements called Generic model <.....2431> and replace them with prefab 716520 prefab floor 1000x2431

    is this possible...
     
  18. apocaliptika

    apocaliptika

    Joined:
    Jul 22, 2017
    Posts:
    1
    This is an update from @_creatio_ and @Elzean 's and @Hypertectonic's version, with an extra bool for keeping the Child Index in the Hierarchy. It's an amazing script and made my life so much easier except for the fact that I had to keep resenting the sibling index.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditor.SceneManagement;
    4. using System.Collections.Generic;
    5.  
    6. // COMMUNITY THREAD LINK https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    7. // CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
    8. // March 2010
    9. //Modified by Kristian Helle Jespersen
    10. //June 2011
    11. //Modified by Connor Cadellin McKee for Excamedia
    12. //April 2015
    13. //Modified by Fernando Medina (fermmmm)
    14. //April 2015
    15. //Modified by Julien Tonsuso (www.julientonsuso.com)
    16. //July 2015
    17. //Changed into editor window and added instant preview in scene view
    18. //Modified by Alex Dovgodko
    19. //June 2017
    20. //Made changes to make things work with Unity 5.6.1
    21. //March 2018
    22. //Added link to community thread, booleans to chose if scale and rotation are applied, mark scene as dirty, changed menu item to tools. By Hyper
    23. //May 2018
    24. //Added KeepPlaceInHeirarchy self explanatory
    25. //Modified by Virgil Iordan
    26. public class ReplaceWithPrefab:EditorWindow {
    27.     public GameObject Prefab;
    28.     public GameObject[] ObjectsToReplace;
    29.     public List<GameObject> TempObjects = new List<GameObject>();
    30.     public bool KeepOriginalNames = true;
    31.     public bool EditMode = false;
    32.     public bool ApplyRotation = true;
    33.     public bool ApplyScale = true;
    34.     public bool KeepPlaceInHeirarchy = false;
    35.     // Add menu named "My Window" to the Window menu
    36.     [MenuItem("Tools/ReplaceWithPrefab")]
    37.     static void Init() {
    38.         // Get existing open window or if none, make a new one:
    39.         ReplaceWithPrefab window = (ReplaceWithPrefab)EditorWindow.GetWindow(typeof(ReplaceWithPrefab));
    40.         window.Show();
    41.     }
    42.     void OnSelectionChange() {
    43.         GetSelection();
    44.         Repaint();
    45.     }
    46.  
    47.     void CheckParent() {
    48.     }
    49.  
    50.     void OnGUI() {
    51.         EditMode = GUILayout.Toggle(EditMode,"Edit");
    52.         if (GUI.changed) {
    53.             if (EditMode)
    54.                 GetSelection();
    55.             else
    56.                 ResetPreview();
    57.         }
    58.         KeepOriginalNames = GUILayout.Toggle(KeepOriginalNames,"Keep names");
    59.         ApplyRotation = GUILayout.Toggle(ApplyRotation,"Apply rotation");
    60.         ApplyScale = GUILayout.Toggle(ApplyScale,"Apply scale");
    61.         KeepPlaceInHeirarchy = GUILayout.Toggle(KeepPlaceInHeirarchy,"Keep Place In Heirarchy");
    62.         GUILayout.Space(5);
    63.         if (EditMode) {
    64.             ResetPreview();
    65.  
    66.             GUI.color = Color.yellow;
    67.             if (Prefab != null) {
    68.                 GUILayout.Label("Prefab: ");
    69.                 GUILayout.Label(Prefab.name);
    70.             } else {
    71.                 GUILayout.Label("No prefab selected");
    72.             }
    73.             GUI.color = Color.white;
    74.  
    75.             GUILayout.Space(5);
    76.             GUILayout.BeginScrollView(new Vector2());
    77.             foreach (GameObject go in ObjectsToReplace) {
    78.                 GUILayout.Label(go.name);
    79.                 if (Prefab != null) {
    80.                     GameObject newObject;
    81.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(Prefab);
    82.                     newObject.transform.SetParent(go.transform.parent,true);
    83.                     newObject.transform.localPosition = go.transform.localPosition;
    84.                     if (ApplyRotation) {
    85.                         newObject.transform.localRotation = go.transform.localRotation;
    86.                     }
    87.                     if (ApplyScale) {
    88.                         newObject.transform.localScale = go.transform.localScale;
    89.                     }
    90.                     TempObjects.Add(newObject);
    91.                     if (KeepOriginalNames) {
    92.                         newObject.transform.name = go.transform.name;
    93.                     }
    94.                     go.SetActive(false);
    95.                     if (KeepPlaceInHeirarchy) {
    96.                         newObject.transform.SetSiblingIndex(go.transform.GetSiblingIndex());
    97.                     }
    98.                 }
    99.             }
    100.             GUILayout.EndScrollView();
    101.             GUILayout.Space(5);
    102.             GUILayout.BeginHorizontal();
    103.             if (GUILayout.Button("Apply")) {
    104.                 foreach (GameObject go in ObjectsToReplace) {
    105.                     DestroyImmediate(go);
    106.                 }
    107.                 EditMode = false;
    108.                 EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // So that we don't forget to save...
    109.             };
    110.             if (GUILayout.Button("Cancel")) {
    111.                 ResetPreview();
    112.                 EditMode = false;
    113.             };
    114.             GUILayout.EndHorizontal();
    115.         } else {
    116.             ObjectsToReplace = new GameObject[0];
    117.             TempObjects.Clear();
    118.             Prefab = null;
    119.         }
    120.  
    121.     }
    122.     void OnDestroy() {
    123.         ResetPreview();
    124.     }
    125.     void GetSelection() {
    126.         if (EditMode && Selection.activeGameObject != null) {
    127.             PrefabType t = PrefabUtility.GetPrefabType(Selection.activeGameObject);
    128.             if (t == PrefabType.Prefab) //Here goes the fix
    129.             {
    130.                 Prefab = Selection.activeGameObject;
    131.             } else {
    132.                 ResetPreview();
    133.                 ObjectsToReplace = Selection.gameObjects;
    134.             }
    135.         }
    136.     }
    137.     void ResetPreview() {
    138.         if (TempObjects != null) {
    139.             foreach (GameObject go in TempObjects) {
    140.                 DestroyImmediate(go);
    141.             }
    142.         }
    143.         foreach (GameObject go in ObjectsToReplace) {
    144.             go.SetActive(true);
    145.         }
    146.         TempObjects.Clear();
    147.     }
    148. }
     
    NeatWolf likes this.
  19. Paul-Swanson

    Paul-Swanson

    Joined:
    Jan 22, 2014
    Posts:
    317
    Old thread, I know, and I don't care. Consider this a sticky, since this was so useful. Magnificent
     
  20. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    I needed this right today, thanks guys! :)
     
  21. Creepy-Cat

    Creepy-Cat

    Joined:
    Dec 4, 2013
    Posts:
    1,069
    Sorry for bump, but thanks for this script, you just save my life on a big gameobject replacing process... Usually i do those crap by hand...
     
  22. Paul-Swanson

    Paul-Swanson

    Joined:
    Jan 22, 2014
    Posts:
    317
    This really needs to be a built in feature....just saying *winkwink nudge nudge*
     
    Hypertectonic and Creepy-Cat like this.
  23. master_rigel

    master_rigel

    Joined:
    Mar 24, 2014
    Posts:
    69
    I am now using this script. I've bookmarked this page for later.
     
  24. alargastudio

    alargastudio

    Joined:
    Apr 18, 2017
    Posts:
    11
    awesome script, you guys just save my lives
    thank you so much!
     
  25. bansheesoft

    bansheesoft

    Joined:
    Oct 3, 2014
    Posts:
    62
    Quickly tossed this together if anyone needs it off this code.
    Drop the prefab to use to replace in the top field then the selected are in the list out. Apply to switch out..
    Simple and works. Only tested a little but it is doing my job.
    Thanks!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. // CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
    4. // March 2010
    5. //Modified by Kristian Helle Jespersen
    6. //June 2011
    7. //Modified by Connor Cadellin McKee for Excamedia
    8. //April 2015
    9. //Modified by Fernando Medina (fermmmm)
    10. //April 2015
    11. //Modified  by Ryan Mitchell (RyanMitchellGames.WordPress.com)
    12. //January 2019
    13.  
    14. public class ReplaceGameObjects : ScriptableWizard
    15. {
    16.     public GameObject[] ObjectsToReplace;
    17.     Object obj = null;
    18.  
    19.     [MenuItem("Tools/Replace GameObjects")]
    20.     static void CreateWizard()
    21.     {
    22.         ReplaceGameObjects window = ScriptableObject.CreateInstance(typeof(ReplaceGameObjects)) as ReplaceGameObjects;
    23.         window.ShowUtility();
    24.     }
    25.  
    26.     void Apply()
    27.     {
    28.         Object[] gos = Selection.objects;
    29.         foreach (Object go in  gos)
    30.         {
    31.             GameObject oldObject = go as GameObject;
    32.             GameObject newObjectHold = obj as GameObject;
    33.             if (oldObject &&
    34.                 newObjectHold)
    35.             {
    36.                 GameObject newObject = (GameObject)PrefabUtility.InstantiatePrefab(newObjectHold);
    37.  
    38.                 newObject.transform.SetParent(oldObject.transform.parent, true);
    39.                 newObject.transform.localPosition = oldObject.transform.localPosition;
    40.                 newObject.transform.localRotation = oldObject.transform.localRotation;
    41.                 newObject.transform.localScale = oldObject.transform.localScale;
    42.                 newObject.transform.name = oldObject.transform.name;
    43.                 DestroyImmediate(go);
    44.             }
    45.         }
    46.     }
    47.  
    48.     void OnGUI()
    49.     {
    50.         obj = EditorGUILayout.ObjectField("Label:", obj, typeof(GameObject), true);
    51.  
    52.         string selectedName = "Selected:\r\n";
    53.         Object[] gos = Selection.objects;
    54.         foreach (Object go in gos)
    55.         {
    56.             selectedName += go.name + "\r\n";
    57.         }
    58.         EditorGUILayout.TextArea( selectedName);
    59.  
    60.         if (GUILayout.Button("Apply"))
    61.             Apply();
    62.  
    63.         if (GUILayout.Button("Close"))
    64.             Close();
    65.  
    66.     }
    67.  
    68.     void OnInspectorUpdate()
    69.     {
    70.         Repaint();
    71.     }
    72. }
     
    KiddUniverse likes this.
  26. KiddUniverse

    KiddUniverse

    Joined:
    Oct 13, 2016
    Posts:
    115
    hey banshee that works great, thanks. itd be sweet if the apply button was at the top of the gui for when dealing with hundreds of objects, or if clicking enter would apply it, as otherwise the button goes off screen. as is you'd have to do it in groups of like 30 or less, but still works. probably just a matter of moving a couple lines. thanks again.
     
  27. dbyeajee_RaveAC

    dbyeajee_RaveAC

    Joined:
    Mar 23, 2018
    Posts:
    1
    Building on the shoulders of giants @apocaliptika, @Elzean , @Hypertectonic , @_creatio_ . Sorry if I missed anyone.
    Added numbering to the instantiated prefabs as an identifier, also checks for numbers used already.
    Follows the default Unity naming convention i.e. "Cube (1)"
    Finds the "space" character in the name to identify where the number is, then strips the brackets.
    The code is not that elegant and doesn't account for custom naming conventions, but hopefully someone can improve it.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditor.SceneManagement;
    4. using System.Collections.Generic;
    5. // COMMUNITY THREAD LINK https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    6. // CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
    7. // March 2010
    8. //Modified by Kristian Helle Jespersen
    9. //June 2011
    10. //Modified by Connor Cadellin McKee for Excamedia
    11. //April 2015
    12. //Modified by Fernando Medina (fermmmm)
    13. //April 2015
    14. //Modified by Julien Tonsuso (www.julientonsuso.com)
    15. //July 2015
    16. //Changed into editor window and added instant preview in scene view
    17. //Modified by Alex Dovgodko
    18. //June 2017
    19. //Made changes to make things work with Unity 5.6.1
    20. //March 2018
    21. //Added link to community thread, booleans to chose if scale and rotation are applied, mark scene as dirty, changed menu item to tools. By Hyper
    22. //May 2018
    23. //Added KeepPlaceInHeirarchy self explanatory
    24. //Modified by Virgil Iordan
    25. //Added unique numbering identifier in the hierarchy to each newly instantiated prefab, also accounts for existing numbers
    26. //Modified by Dev Bye-A-Jee, Sanjay Sen & Nick Rodriguez for Ravensbourne University London
    27. //January 2019
    28. public class ReplaceWithPrefab:EditorWindow {
    29.     public GameObject Prefab;
    30.     public GameObject[] ObjectsToReplace;
    31.     public List<GameObject> TempObjects = new List<GameObject>();
    32.     public bool KeepOriginalNames = true;
    33.     public bool EditMode = false;
    34.     public bool ApplyRotation = true;
    35.     public bool ApplyScale = true;
    36.     public bool KeepPlaceInHeirarchy = false;
    37.     // Add menu named "My Window" to the Window menu
    38.     [MenuItem("Tools/ReplaceWithPrefab")]
    39.     static void Init() {
    40.         // Get existing open window or if none, make a new one:
    41.         ReplaceWithPrefab window = (ReplaceWithPrefab)EditorWindow.GetWindow(typeof(ReplaceWithPrefab));
    42.         window.Show();
    43.     }
    44.     void OnSelectionChange() {
    45.         GetSelection();
    46.         Repaint();
    47.     }
    48.     void CheckParent() {
    49.     }
    50.     void OnGUI() {
    51.         EditMode = GUILayout.Toggle(EditMode,"Edit");
    52.         if (GUI.changed) {
    53.             if (EditMode)
    54.                 GetSelection();
    55.             else
    56.                 ResetPreview();
    57.         }
    58.         KeepOriginalNames = GUILayout.Toggle(KeepOriginalNames,"Keep names");
    59.         ApplyRotation = GUILayout.Toggle(ApplyRotation,"Apply rotation");
    60.         ApplyScale = GUILayout.Toggle(ApplyScale,"Apply scale");
    61.         KeepPlaceInHeirarchy = GUILayout.Toggle(KeepPlaceInHeirarchy,"Keep Place In Hierarchy");
    62.         GUILayout.Space(5);
    63.         if (EditMode) {
    64.             ResetPreview();
    65.             GUI.color = Color.yellow;
    66.             if (Prefab != null) {
    67.                 GUILayout.Label("Prefab: ");
    68.                 GUILayout.Label(Prefab.name);
    69.             } else {
    70.                 GUILayout.Label("No prefab selected");
    71.             }
    72.             GUI.color = Color.white;
    73.             GUILayout.Space(5);
    74.             GUILayout.BeginScrollView(new Vector2());
    75.             foreach (GameObject go in ObjectsToReplace) {
    76.                 GUILayout.Label(go.name);
    77.                 if (Prefab != null) {
    78.                     GameObject newObject;
    79.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(Prefab);
    80.                     newObject.transform.SetParent(go.transform.parent,true);
    81.                     newObject.transform.localPosition = go.transform.localPosition;
    82.                     if (ApplyRotation) {
    83.                         newObject.transform.localRotation = go.transform.localRotation;
    84.                     }
    85.                     if (ApplyScale) {
    86.                         newObject.transform.localScale = go.transform.localScale;
    87.                     }
    88.                     TempObjects.Add(newObject);
    89.              
    90.                     if (KeepOriginalNames) {
    91.                         newObject.transform.name = go.transform.name;
    92.                     }
    93.                     go.SetActive(false);
    94.                  
    95.                     if (KeepPlaceInHeirarchy) {
    96.                         newObject.transform.SetSiblingIndex(go.transform.GetSiblingIndex());
    97.                     }
    98.                 }
    99.             }
    100.             GUILayout.EndScrollView();
    101.             GUILayout.Space(5);
    102.             GUILayout.BeginHorizontal();
    103.             if (GUILayout.Button("Apply")) {
    104.                 if (!KeepOriginalNames) {
    105.                     int count = 0;
    106.                     List<int> ExistingNumbers = new List<int>();
    107.                     foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
    108.                     {
    109.                         if (obj.name.Contains(Prefab.name))
    110.                         {
    111.                             string[] stringSplit = obj.name.Split(' '); // number deliminator, setup for default Unity naming convention i.e "Cube (1)"
    112.                             if (stringSplit.Length > 1) {
    113.                                 char[] charsToTrim = {'(', ')'}; // extra characters to trim
    114.                                  string num = stringSplit[1].Trim(charsToTrim); // substring which contains number
    115.                                 int x = int.Parse(num); // convert string to number
    116.                                 ExistingNumbers.Add(x);
    117.                              }
    118.                         }
    119.                     }
    120.                     foreach (GameObject go in TempObjects) {
    121.                         count++;
    122.                          if (ExistingNumbers.Count > 0) {
    123.                             int i = 0;
    124.                             while (i < (ExistingNumbers.Count)) {
    125.                                 if (count == (ExistingNumbers[i])) {
    126.                                     count++;
    127.                                     i = 0;
    128.                                 } else {
    129.                                     i++;
    130.                                 }
    131.                             }
    132.                         }
    133.                         go.transform.name = go.transform.name + " (" + count + ")";
    134.                     }
    135.                 }
    136.                 foreach (GameObject go in ObjectsToReplace) {
    137.                     DestroyImmediate(go);
    138.                 }
    139.                 EditMode = false;
    140.                 EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // So that we don't forget to save...
    141.             };
    142.             if (GUILayout.Button("Cancel")) {
    143.                 ResetPreview();
    144.                 EditMode = false;
    145.             };
    146.             GUILayout.EndHorizontal();
    147.         } else {
    148.             ObjectsToReplace = new GameObject[0];
    149.             TempObjects.Clear();
    150.             Prefab = null;
    151.         }
    152.     }
    153.     void OnDestroy() {
    154.         ResetPreview();
    155.     }
    156.     void GetSelection() {
    157.         if (EditMode && Selection.activeGameObject != null) {
    158.             PrefabType t = PrefabUtility.GetPrefabType(Selection.activeGameObject);
    159.             if (t == PrefabType.Prefab) //Here goes the fix
    160.             {
    161.                 Prefab = Selection.activeGameObject;
    162.             } else {
    163.                 ResetPreview();
    164.                 ObjectsToReplace = Selection.gameObjects;
    165.             }
    166.         }
    167.     }
    168.     void ResetPreview() {
    169.         if (TempObjects != null) {
    170.             foreach (GameObject go in TempObjects) {
    171.                 DestroyImmediate(go);
    172.             }
    173.         }
    174.         foreach (GameObject go in ObjectsToReplace) {
    175.             go.SetActive(true);
    176.         }
    177.         TempObjects.Clear();
    178.     }
    179. }
     
    sarebots2, Hypertectonic and Elzean like this.
  28. dubiduboni_unity

    dubiduboni_unity

    Joined:
    Feb 11, 2019
    Posts:
    116
    My script.

    I added a search bar to easily searching for objects to replace. for example type in Cube(Clone) or Cube and it will find all the Cube objects in the Hierarchy including children and will replace them with a button click.

    Or a single replace.

    Added keep names option and undo option.
    Also it keep the replaced objects index place in the hierarchy and also if you have more then one scenes it will keep the place of the replaced gameobject according to on what scene it was changed.



    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.IO;
    6. using System.Linq;
    7. using UnityEditor;
    8. using UnityEngine;
    9. using UnityEngine.SceneManagement;
    10. using UnityEngine.UI;
    11.  
    12. public class PrefabReplace : EditorWindow
    13. {
    14.     [SerializeField] private GameObject prefab;
    15.     private bool selectionChanged;
    16.     private string objectsToSearch = "";
    17.     private List<GameObject> foundObjects = new List<GameObject>();
    18.     private GUIStyle guiStyle = new GUIStyle(); //create a new variable
    19.     private int count = 0;
    20.     private bool addFoundObjects;
    21.     private bool keepNames = true;
    22.  
    23.     [MenuItem("Tools/Prefab Replace")]
    24.     static void CreateReplaceWithPrefab()
    25.     {
    26.         int width = 340;
    27.         int height = 370;
    28.  
    29.         int x = (Screen.currentResolution.width - width) / 2;
    30.         int y = (Screen.currentResolution.height - height) / 2;
    31.      
    32.         GetWindow<PrefabReplace>().position = new Rect(x, y, width, height);
    33.     }
    34.  
    35.     private void OnGUI()
    36.     {
    37.         guiStyle.fontSize = 15; //change the font size
    38.         Searching();
    39.         GUILayout.Space(10);
    40.         Replacing();
    41.         GUILayout.Space(50);
    42.         Settings();
    43.     }
    44.  
    45.     private void Searching()
    46.     {
    47.         //GUI.Label(new Rect(10, 15, 150, 20), "Search by name", guiStyle);
    48.         objectsToSearch = GUI.TextField(new Rect(90, 35, 150, 20), objectsToSearch, 25);
    49.  
    50.         if (objectsToSearch != "")
    51.         {
    52.             GUI.enabled = true;
    53.         }
    54.         else
    55.         {
    56.             GUI.enabled = false;
    57.             count = 0;
    58.         }
    59.         GUILayout.Space(15);
    60.         if (GUILayout.Button("Search"))
    61.         {
    62.             foundObjects = new List<GameObject>();
    63.             count = 0;
    64.  
    65.             foreach (GameObject gameObj in GameObject.FindObjectsOfType<GameObject>())
    66.             {
    67.                 if (gameObj.name == objectsToSearch)//.Contains(objectsToSearch))// == objectsToSearch)
    68.                 {
    69.                     count += 1;
    70.                     foundObjects.Add(gameObj);
    71.                     foreach (Transform child in gameObj.transform)
    72.                     {
    73.                         count += 1;
    74.                         foundObjects.Add(child.gameObject);
    75.                     }
    76.                 }
    77.             }
    78.  
    79.             if(foundObjects.Count == 0)
    80.             {
    81.                 count = 0;
    82.             }
    83.         }
    84.  
    85.         GUI.enabled = true;
    86.         EditorGUI.LabelField(new Rect(90, 65, 210, 15), "Number of found objects and childs");
    87.         GUI.TextField(new Rect(90, 80, 60, 15), count.ToString(), 25);
    88.  
    89.         GUILayout.Space(100);
    90.         if (count > 0)
    91.         {
    92.             GUI.enabled = true;
    93.         }
    94.         else
    95.         {
    96.             GUI.enabled = false;
    97.         }
    98.         if (GUILayout.Button("Replace found objects"))
    99.         {
    100.             if (prefab != null)      
    101.             {
    102.                 InstantiatePrefab(foundObjects);
    103.             }
    104.         }
    105.  
    106.         GUI.enabled = true;
    107.     }
    108.  
    109.     private void Replacing()
    110.     {
    111.         GUILayout.Space(20);
    112.         GUILayout.BeginVertical(GUI.skin.box);
    113.         GUILayout.Label("Replacing");
    114.         GUILayout.Space(20);
    115.  
    116.         prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
    117.  
    118.         var selection = Selection.objects.OfType<GameObject>().ToList();
    119.  
    120.         if (selectionChanged)
    121.         {
    122.             if (selection.Count == 0)
    123.                 GUI.enabled = false;
    124.  
    125.             for (var i = selection.Count - 1; i >= 0; --i)
    126.             {
    127.                 var selectedObject = selection[i];
    128.                 if (prefab != null && selection.Count > 0 &&
    129.                     selectedObject.scene.name != null
    130.                     && prefab != PrefabUtility
    131.                     .GetCorrespondingObjectFromSource(selectedObject))
    132.                 {
    133.                     GUI.enabled = true;
    134.                 }
    135.                 else
    136.                 {
    137.                     GUI.enabled = false;
    138.                 }
    139.             }
    140.         }
    141.         else
    142.         {
    143.             GUI.enabled = false;
    144.         }
    145.  
    146.         if (GUILayout.Button("Replace"))
    147.         {
    148.             InstantiatePrefab(selection);
    149.             selectionChanged = false;
    150.         }
    151.  
    152.         GUILayout.Space(10);
    153.         GUI.enabled = true;
    154.         EditorGUILayout.LabelField("Selection count: " + Selection.objects.OfType<GameObject>().Count());
    155.  
    156.         GUILayout.EndVertical();
    157.     }
    158.  
    159.     private void Settings()
    160.     {
    161.         keepNames = GUILayout.Toggle(keepNames, "Keep Names");
    162.     }
    163.  
    164.     private void OnInspectorUpdate()
    165.     {
    166.         Repaint();
    167.     }
    168.  
    169.     private void OnSelectionChange()
    170.     {
    171.         selectionChanged = true;
    172.     }
    173.  
    174.     private void InstantiatePrefab(List<GameObject> selection)
    175.     {
    176.         if (prefab != null && selection.Count > 0)
    177.         {
    178.             for (var i = selection.Count - 1; i >= 0; --i)
    179.             {
    180.                 var selected = selection[i];
    181.                 Component[] components = selected.GetComponents(typeof(MonoBehaviour));
    182.                 if (components.Length == 0)
    183.                 {
    184.                     SceneManager.SetActiveScene(SceneManager.GetSceneByName(selected.scene.name));
    185.  
    186.                     var prefabType = PrefabUtility.GetPrefabAssetType(prefab);
    187.                     GameObject newObject;
    188.  
    189.                     if (prefabType == PrefabAssetType.Regular)
    190.                     {
    191.                         newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    192.                     }
    193.                     else
    194.                     {
    195.                         newObject = Instantiate(prefab);
    196.  
    197.                         if (keepNames == false)
    198.                         {
    199.                             newObject.name = prefab.name;
    200.                         }
    201.                     }
    202.                     if (newObject == null)
    203.                     {
    204.                         Debug.LogError("Error instantiating prefab");
    205.                         break;
    206.                     }
    207.  
    208.                     Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
    209.                     newObject.transform.parent = selected.transform.parent;
    210.                     newObject.transform.localPosition = selected.transform.localPosition;
    211.                     newObject.transform.localRotation = selected.transform.localRotation;
    212.                     newObject.transform.localScale = selected.transform.localScale;
    213.                     newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
    214.                     if (keepNames == true)
    215.                     {
    216.                         newObject.name = selected.name;
    217.                     }
    218.                     Undo.DestroyObjectImmediate(selected);
    219.                 }
    220.             }
    221.         }
    222.     }
    223. }
    224.  
     
  29. phobos2077

    phobos2077

    Joined:
    Feb 10, 2018
    Posts:
    350
    Yes another version but with slightly different task. I already used a bunch of prefabs on several scenes and needed to replace every instance of each prefab with a new version (regular prefabs with variant prefabs).
    So you open this window, put all of your old prefabs in the first array, then all of corresponding new prefabs in the second array (must be in the same order). Then you open your old scenes one by one and just press the button, it will replace everything for you. No need to search and selecting anything.

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEditor;
    6. using UnityEngine.SceneManagement;
    7.  
    8. public class ReplacePrefabs : EditorWindow
    9. {
    10.     [SerializeField]
    11.     private GameObject[] oldPrefabs;
    12.  
    13.     [SerializeField]
    14.     private GameObject[] newPrefabs;
    15.  
    16.     private SerializedObject serialized;
    17.  
    18.     private void OnEnable()
    19.     {
    20.         serialized = new SerializedObject(this);
    21.     }
    22.  
    23.     [MenuItem("Tools/Replace Prefabs")]
    24.     static void CreateReplaceWithPrefab()
    25.     {
    26.         EditorWindow.GetWindow<ReplacePrefabs>();
    27.     }
    28.  
    29.     private void OnGUI()
    30.     {
    31.         EditorGUILayout.PropertyField(serialized.FindProperty(nameof(oldPrefabs)), new GUIContent("Old Prefabs"), true);
    32.         EditorGUILayout.PropertyField(serialized.FindProperty(nameof(newPrefabs)), new GUIContent("New Prefabs"), true);
    33.         serialized.ApplyModifiedProperties();
    34.  
    35.         if (GUILayout.Button("Replace"))
    36.         {
    37.             var replaceDict = new Dictionary<GameObject, GameObject>();
    38.             var numPairs = Mathf.Min(oldPrefabs.Length, newPrefabs.Length);
    39.             for (int i = 0; i < numPairs; i++)
    40.             {
    41.                 if (oldPrefabs[i] && newPrefabs[i] && PrefabUtility.IsPartOfAnyPrefab(newPrefabs[i]))
    42.                 {
    43.                     replaceDict.Add(oldPrefabs[i], newPrefabs[i]);
    44.                 }
    45.             }
    46.  
    47.             var scene = SceneManager.GetActiveScene();
    48.             var rootObjects = scene.GetRootGameObjects();
    49.             int replaceCount = 0;
    50.             foreach (var go in rootObjects)
    51.             {
    52.                 replaceCount += ReplaceForObjectRecursive(go, replaceDict);
    53.             }
    54.             Debug.Log($"Replaced {replaceCount} game objects.");
    55.         }
    56.  
    57.         GUI.enabled = false;
    58.     }
    59.  
    60.     private int ReplaceForObjectRecursive(GameObject go, Dictionary<GameObject, GameObject> replaceDict)
    61.     {
    62.         var sourcePrefab = GetObjectPrefab(go);
    63.         if (!sourcePrefab || !replaceDict.ContainsKey(sourcePrefab))
    64.         {
    65.             int replaceCount = 0;
    66.             foreach (Transform child in go.transform)
    67.             {
    68.                 replaceCount += ReplaceForObjectRecursive(child.gameObject, replaceDict);
    69.             }
    70.             return replaceCount;
    71.         }
    72.  
    73.         var prefab = replaceDict[sourcePrefab];
    74.         var newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    75.         if (newObject == null)
    76.         {
    77.             Debug.LogError("Error instantiating prefab");
    78.             return 0;
    79.         }
    80.  
    81.         Undo.RegisterCreatedObjectUndo(newObject, "Replace Prefabs");
    82.         newObject.transform.parent = go.transform.parent;
    83.         newObject.transform.localPosition = go.transform.localPosition;
    84.         newObject.transform.localRotation = go.transform.localRotation;
    85.         newObject.transform.localScale = go.transform.localScale;
    86.         newObject.transform.SetSiblingIndex(go.transform.GetSiblingIndex());
    87.         Undo.DestroyObjectImmediate(go);
    88.         return 1;
    89.     }
    90.  
    91.     private GameObject GetObjectPrefab(GameObject instance)
    92.     {
    93.         var root = PrefabUtility.GetNearestPrefabInstanceRoot(instance);
    94.         return root ? PrefabUtility.GetCorrespondingObjectFromSource(root) : null;
    95.     }
    96. }
    97.  
    PS: I wouldn't have needed this if Unity had better logic for replacing prefab assets. If I just drag the new prefab asset on the old one, Unity prompts for replacement and it will replace the instances in every scene. The problem is transform will be reset as well - this makes such replacement useless if you have already placed the old prefab in your scenes. It could still be useful for prefabs are never placed in scenes but always instantiated.
     
    Hypertectonic likes this.
  30. rohitvishwakarma1819

    rohitvishwakarma1819

    Joined:
    Feb 15, 2018
    Posts:
    14
    Thanks but the transform of the gameobject are not copying into the prefab instance.
     
  31. deLord

    deLord

    Joined:
    Oct 11, 2014
    Posts:
    306
    Not sure if I used an unripe version of the script but from what I see nobody took into consideration that these objects may be referenced by other GameObjects:
    My HUDManager GO has a reference to several buttons. Using Alt + Drag-Prefab will just override the old one WITHOUT the possibility of using undo, so save before you try this out!
    The script does properly replace the object with the prefab but the references are destroyed. Also, buttons do not save their onClick() contents. And for me these were the main reason I searched for a solution :)
     
    leni8ec and NeatWolf like this.
  32. Zan_Kievit

    Zan_Kievit

    Joined:
    Mar 24, 2018
    Posts:
    14
    I've made some changes to the last modification of @Elzean's version from @dbyeajee_RaveAC

    It's now compatible with the new prefab system introduced in Unity 2018.3, has undo functionality, and is a little more user friendly.

    upload_2020-3-22_16-45-48.png

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditor.SceneManagement;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7. // COMMUNITY THREAD LINK https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    8. // CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
    9. // March 2010
    10. //Modified by Kristian Helle Jespersen
    11. //June 2011
    12. //Modified by Connor Cadellin McKee for Excamedia
    13. //April 2015
    14. //Modified by Fernando Medina (fermmmm)
    15. //April 2015
    16. //Modified by Julien Tonsuso (www.julientonsuso.com)
    17. //July 2015
    18. //Changed into editor window and added instant preview in scene view
    19. //Modified by Alex Dovgodko
    20. //June 2017
    21. //Made changes to make things work with Unity 5.6.1
    22. //March 2018
    23. //Added link to community thread, booleans to chose if scale and rotation are applied, mark scene as dirty, changed menu item to tools. By Hyper
    24. //May 2018
    25. //Added KeepPlaceInHeirarchy self explanatory
    26. //Modified by Virgil Iordan
    27. //Added unique numbering identifier in the hierarchy to each newly instantiated prefab, also accounts for existing numbers
    28. //Modified by Dev Bye-A-Jee, Sanjay Sen & Nick Rodriguez for Ravensbourne University London
    29. //January 2019
    30. //Modified by Zan Kievit
    31. //Made compatible with the new Prefab system of Unity 2018. Made more user friendly and added undo. Last tested on Unity 2019.3.6f1
    32. //March 2020
    33.  
    34. public class ReplaceWithPrefab : EditorWindow
    35. {
    36.     public GameObject Prefab;
    37.     public List<GameObject> ObjectsToReplace = new List<GameObject>();
    38.     public List<GameObject> TempObjects = new List<GameObject>();
    39.     public bool EditMode = false;
    40.     public bool KeepOriginalNames = true;
    41.     public bool ApplyRotation = true;
    42.     public bool ApplyScale = true;
    43.     public bool KeepPlaceInHierarchy = false;
    44.  
    45.     Vector2 scrollPosition;
    46.  
    47.     // Add menu named "ReplaceWithPrefab" to the Tool menu
    48.     [MenuItem("Tools/ReplaceWithPrefab")]
    49.     public static void Init ()
    50.     {
    51.         // Get existing open window or if none, make a new one:
    52.         ReplaceWithPrefab window = (ReplaceWithPrefab)GetWindow(typeof(ReplaceWithPrefab));
    53.         window.Show();
    54.     }
    55.  
    56.     void OnSelectionChange ()
    57.     {
    58.         GetSelection();
    59.         Repaint();
    60.     }
    61.  
    62.     void OnGUI ()
    63.     {
    64.         GUILayout.BeginHorizontal(EditorStyles.toolbar);
    65.         EditMode = GUILayout.Toggle(EditMode,new GUIContent("Edit", "Start using this feature"), EditorStyles.toolbarButton);
    66.         GUILayout.FlexibleSpace();
    67.         KeepOriginalNames = GUILayout.Toggle(KeepOriginalNames, "Keep names", EditorStyles.toolbarButton);
    68.         ApplyRotation = GUILayout.Toggle(ApplyRotation, "Apply rotation", EditorStyles.toolbarButton);
    69.         ApplyScale = GUILayout.Toggle(ApplyScale, "Apply scale", EditorStyles.toolbarButton);
    70.         KeepPlaceInHierarchy = GUILayout.Toggle(KeepPlaceInHierarchy, "Keep Place In Hierarchy", EditorStyles.toolbarButton);
    71.         GUILayout.EndHorizontal();
    72.  
    73.         if (GUI.changed)
    74.         {
    75.             if (EditMode)
    76.                 GetSelection();
    77.             else
    78.                 ResetPreview();
    79.         }
    80.  
    81.         GUILayout.Space(5);
    82.         if (EditMode)
    83.         {
    84.             ResetPreview();
    85.             if (Prefab != null)
    86.             {
    87.                 GUILayout.Label("Prefab: ", EditorStyles.boldLabel);
    88.                 GUILayout.Label(Prefab.name);
    89.                 GUILayout.Space(10);
    90.  
    91.                 if (ObjectsToReplace.Count > 0)
    92.                 {
    93.                     GUILayout.Label(new GUIContent("Objects to be Replaced:", "Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    94.                     ObjectsToReplace.Sort(NameCompare);
    95.                     scrollPosition = GUILayout.BeginScrollView(scrollPosition, EditorStyles.helpBox);
    96.                     foreach (GameObject go in ObjectsToReplace)
    97.                     {
    98.                         GUILayout.BeginHorizontal(EditorStyles.toolbar);
    99.                         GUILayout.Label(go.name);
    100.                         GUILayout.EndHorizontal();
    101.                     }
    102.                     GUILayout.Space(2);
    103.                     GUILayout.EndScrollView();
    104.                 }
    105.                 else
    106.                 {
    107.                     GUILayout.Label(new GUIContent("Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    108.                 }
    109.             }
    110.             else
    111.             {
    112.                 GUILayout.Label("Select a Prefab to replace objects with", EditorStyles.boldLabel);
    113.             }
    114.          
    115.             GUILayout.Space(5);
    116.             GUILayout.BeginHorizontal();
    117.  
    118.             if(Prefab != null && ObjectsToReplace.Count > 0)
    119.             {
    120.                 if (GUILayout.Button("Apply"))
    121.                 {
    122.                     if (!KeepOriginalNames)
    123.                     {
    124.                         int count = 0;
    125.                         List<int> ExistingNumbers = new List<int>();
    126.                         foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
    127.                         {
    128.                             if (obj.name.Contains(Prefab.name))
    129.                             {
    130.                                 string[] stringSplit = obj.name.Split(' '); // number deliminator, setup for default Unity naming convention i.e "Cube (1)"
    131.                                 if (stringSplit.Length > 1)
    132.                                 {
    133.                                     char[] charsToTrim = { '(', ')' }; // extra characters to trim
    134.                                     string num = stringSplit[1].Trim(charsToTrim); // substring which contains number
    135.                                     int x = int.Parse(num); // convert string to number
    136.                                     ExistingNumbers.Add(x);
    137.                                 }
    138.                             }
    139.                         }
    140.                         foreach (GameObject go in TempObjects)
    141.                         {
    142.                             count++;
    143.                             if (ExistingNumbers.Count > 0)
    144.                             {
    145.                                 int i = 0;
    146.                                 while (i < (ExistingNumbers.Count))
    147.                                 {
    148.                                     if (count == (ExistingNumbers[i]))
    149.                                     {
    150.                                         count++;
    151.                                         i = 0;
    152.                                     }
    153.                                     else
    154.                                     {
    155.                                         i++;
    156.                                     }
    157.                                 }
    158.                             }
    159.                             go.transform.name = go.transform.name + " (" + count + ")";
    160.                         }
    161.                     }
    162.                     foreach (GameObject go in ObjectsToReplace)
    163.                     {
    164.                         Replace(go);
    165.                         DestroyImmediate(go);
    166.                     }
    167.                     EditMode = false;
    168.                     EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // So that we don't forget to save...
    169.                 }
    170.                 else if (GUILayout.Button("Cancel"))
    171.                 {
    172.                     ResetPreview();
    173.                     EditMode = false;
    174.                 }
    175.             }
    176.             GUILayout.EndHorizontal();
    177.         }
    178.         else
    179.         {
    180.             ObjectsToReplace.Clear();
    181.             TempObjects.Clear();
    182.             Prefab = null;
    183.         }
    184.     }
    185.  
    186.     void OnDestroy ()
    187.     {
    188.         ResetPreview();
    189.     }
    190.  
    191.     void Replace(GameObject obj)
    192.     {
    193.         GameObject newObject;
    194.         newObject = (GameObject)PrefabUtility.InstantiatePrefab(PrefabUtility.GetCorrespondingObjectFromSource(Prefab)) as GameObject;
    195.         newObject.transform.SetParent(obj.transform.parent, true);
    196.         newObject.transform.localPosition = obj.transform.localPosition;
    197.         if (ApplyRotation)
    198.         {
    199.             newObject.transform.localRotation = obj.transform.localRotation;
    200.         }
    201.         if (ApplyScale)
    202.         {
    203.             newObject.transform.localScale = obj.transform.localScale;
    204.         }
    205.         TempObjects.Add(newObject);
    206.  
    207.         if (KeepOriginalNames)
    208.         {
    209.             newObject.transform.name = obj.transform.name;
    210.         }
    211.  
    212.         if (KeepPlaceInHierarchy)
    213.         {
    214.             newObject.transform.SetSiblingIndex(obj.transform.GetSiblingIndex());
    215.         }
    216.  
    217.         Undo.RegisterCreatedObjectUndo(newObject, "Replaced Objects");
    218.         Undo.DestroyObjectImmediate(obj);
    219.     }
    220.  
    221.     void GetSelection ()
    222.     {
    223.         if (EditMode && Selection.activeGameObject != null)
    224.         {
    225.             PrefabAssetType t = PrefabUtility.GetPrefabAssetType(Selection.activeGameObject);
    226.             if (t == PrefabAssetType.Regular || t == PrefabAssetType.Variant)
    227.             {
    228.                 Prefab = Selection.activeGameObject;
    229.             }
    230.             else
    231.             {
    232.                 ResetPreview();
    233.                 ObjectsToReplace.Clear();
    234.                 foreach (var obj in Selection.gameObjects)
    235.                 {
    236.                     ObjectsToReplace.Add(obj);
    237.                 }
    238.             }
    239.         }
    240.     }
    241.  
    242.     void ResetPreview ()
    243.     {
    244.         if (TempObjects != null)
    245.         {
    246.             foreach (GameObject go in TempObjects)
    247.             {
    248.                 DestroyImmediate(go);
    249.             }
    250.         }
    251.         TempObjects.Clear();
    252.     }
    253.  
    254.     int  NameCompare (Object a, Object b)
    255.     {
    256.         return new CaseInsensitiveComparer().Compare(a.name, b.name);
    257.     }
    258. }
     
  33. Hypertectonic

    Hypertectonic

    Joined:
    Dec 16, 2016
    Posts:
    75
    Excellent! I had to stop using this script some time ago because the incompatibility of the prefab system and I just never found the time to dig into how to fix it.
     
  34. Hypertectonic

    Hypertectonic

    Joined:
    Dec 16, 2016
    Posts:
    75
    @Zan_Kievit so I was testing your changes and found several issues and things that could be improved further:
    • Would not work to replace prefabs in the hierarchy, only-non prefab objects
    • Would not be backwards-compatible for pre-2018.3
    • Would not work with prefabs picked in the project browser.
    So here's the changes:
    • Works with prefabs selected in project browser.
    • Now replaces prefabs in hierarchy too.
    • Backwards compatibility to pre-2018.3 prefab system (needs testing!)
    • Ability to open from right click in hierarchy (much faster usability)!
    • Put Menu entry inside Community folder.
    • Parameters for min/max window size.
    And also did some code cleanup and documentation because it was starting to become unwieldy:
    • Added #region blocks and spacing here and there for readability
    • Extracted a couple methods from huge code blocks
    • Added version numbers
    • Added summary comments to all methods
    • Improved formatting of heading comment
    • Added Community namespace to avoid conflicts
    There are still some known issues in this version in the renaming code:
    • Numbering doesn't work (since?)
    • Throws error when prefab has multiple spaces in name
    It would be nice if someone dug into rewriting the renaming and also making it so you can replace with any GameObject and not just prefabs...

    Code (CSharp):
    1. /*=================== Replace with Prefab ===================
    2.  
    3. Unity Forum Community Thread https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    4.  
    5. Tested in 2018.4.19f1, 2019.3.6f1
    6. Should work in pre-2018.3 versions with old prefab workflow (Needs testing)
    7.  
    8. Changelog and contributors:
    9.  
    10. v1.0.0 (2010-03) Original CopyComponents by Michael L. Croswell for Colorado Game Coders, LLC
    11. v1.1.0 (2011-06) by Kristian Helle Jespersen
    12. v1.2.0 (2015-04) by Connor Cadellin McKee for Excamedia
    13. v1.3.0 (2015-04) by Fernando Medina (fermmmm)
    14. v1.4.0 (2015-07) by Julien Tonsuso (www.julientonsuso.com)
    15. v1.5.0 (2017-06) by Alex Dovgodko
    16.                  Changed into editor window and added instant preview in scene view
    17. v1.6.0 (2018-03) by ???
    18.                  Made changes to make things work with Unity 5.6.1
    19. v1.7.0 (2018-05) by Carlos Diosdado (hypertectonic)
    20.                  Added link to community thread, booleans to choose if scale and rotation are applied, mark scene as dirty, changed menu item
    21. v1.8.0 (2018-??) by Virgil Iordan
    22.                  Added KeepPlaceInHierarchy
    23. v1.9.0 (2019-01) by Dev Bye-A-Jee, Sanjay Sen & Nick Rodriguez for Ravensbourne University London
    24.                  Added unique numbering identifier in the hierarchy to each newly instantiated prefab, also accounts for existing numbers
    25. v2.0.0 (2020-03-22) by Zan Kievit
    26.                     Made compatible with the new Prefab system of Unity 2018. Made more user friendly and added undo.
    27. v2.1.0 (2020-03-22) by Carlos Diosdado (hypertectonic)
    28.                     Added options to use as a utility window (show from right click in the hierarchy), min/max window size,
    29.                     backwards compatibility for old prefab system, works with prefabs selected in project browser, fixed not replacing prefabs,
    30.                     added version numbers, basic documentation, Community namespace to avoid conflicts, cleaned up code for readability.
    31.                    
    32. Known Errors: Rename - numbering doesn't work (since?)
    33.               Rename - throws error when prefab has multiple spaces in their name
    34.  
    35. ============================================================*/
    36.  
    37. using UnityEngine;
    38. using UnityEditor;
    39. using UnityEditor.SceneManagement;
    40. using System.Collections;
    41. using System.Collections.Generic;
    42.  
    43. namespace Community
    44. {
    45.     /// <summary>
    46.     /// An editor tool to replace selected GameObjects with a specified Prefab.
    47.     /// </summary>
    48.     public class ReplaceWithPrefab : EditorWindow
    49.     {
    50.         public GameObject prefab = null;
    51.         public List<GameObject> objectsToReplace = new List<GameObject>();
    52.         public List<GameObject> tempObjects = new List<GameObject>();
    53.         public bool editMode = false;
    54.         public bool keepOriginalNames = false;
    55.         public bool applyRotation = true;
    56.         public bool applyScale = true;
    57.         public bool keepPlaceInHierarchy = true;
    58.  
    59.         private Vector2 windowMinSize = new Vector2(450, 300);
    60.         private Vector2 windowMaxSize = new Vector2(800, 1000);
    61.         private Vector2 scrollPosition;
    62.  
    63.         /// <summary>
    64.         /// Gets or creates a new Replace with Prefab window.
    65.         /// </summary>
    66.         [MenuItem("Tools/Community/Replace with Prefab")]
    67.         [MenuItem("GameObject/Replace with Prefab", false, 0)]
    68.         static void StartWindow()
    69.         {
    70.             ReplaceWithPrefab window = (ReplaceWithPrefab)GetWindow(typeof(ReplaceWithPrefab));
    71.             window.Show();
    72.  
    73.             window.titleContent = new GUIContent("Replace with Prefab");
    74.             window.minSize = window.windowMinSize;
    75.             window.maxSize = window.windowMaxSize;
    76.         }
    77.  
    78.         /// <summary>
    79.         /// Handles getting the selected objects when the selection changes.
    80.         /// </summary>
    81.         void OnSelectionChange()
    82.         {
    83.             GetSelection();
    84.             Repaint();
    85.         }
    86.  
    87.         /// <summary>
    88.         /// Draws the window content: object list, configuration and execution buttons.
    89.         /// </summary>
    90.         void OnGUI()
    91.         {
    92.             #region Draw Top Buttons
    93.             GUILayout.BeginHorizontal(EditorStyles.toolbar);
    94.             {
    95.                 editMode = GUILayout.Toggle(editMode, new GUIContent("Edit", "Start using this feature"), EditorStyles.toolbarButton);
    96.                 GUILayout.FlexibleSpace();
    97.                 keepOriginalNames = GUILayout.Toggle(keepOriginalNames, "Keep names", EditorStyles.toolbarButton);
    98.                 applyRotation = GUILayout.Toggle(applyRotation, "Apply rotation", EditorStyles.toolbarButton);
    99.                 applyScale = GUILayout.Toggle(applyScale, "Apply scale", EditorStyles.toolbarButton);
    100.                 keepPlaceInHierarchy = GUILayout.Toggle(keepPlaceInHierarchy, "Keep Place In Hierarchy", EditorStyles.toolbarButton);
    101.             }
    102.             GUILayout.EndHorizontal();
    103.             #endregion
    104.  
    105.             if (GUI.changed)
    106.             {
    107.                 if (editMode)
    108.                     GetSelection();
    109.                 else
    110.                     ResetPreview();
    111.             }
    112.  
    113.             GUILayout.Space(5);
    114.             if (editMode)
    115.             {
    116.                 ResetPreview();
    117.  
    118.                 #region Draw Prefab and List
    119.                 if (prefab != null)
    120.                 {
    121.                     GUILayout.Label("Prefab: ", EditorStyles.boldLabel);
    122.                     GUILayout.Label(prefab.name);
    123.                     GUILayout.Space(10);
    124.  
    125.                     if (objectsToReplace.Count > 0)
    126.                     {
    127.                         GUILayout.Label(new GUIContent("Objects to be Replaced:", "Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    128.                         objectsToReplace.Sort(NameCompare);
    129.  
    130.                         scrollPosition = GUILayout.BeginScrollView(scrollPosition, EditorStyles.helpBox);
    131.                         {
    132.                             foreach (GameObject go in objectsToReplace)
    133.                             {
    134.                                 GUILayout.BeginHorizontal(EditorStyles.toolbar);
    135.                                 GUILayout.Label(go.name);
    136.                                 GUILayout.EndHorizontal();
    137.                             }
    138.                             GUILayout.Space(2);
    139.                         }
    140.                         GUILayout.EndScrollView();
    141.                     }
    142.                     else
    143.                     {
    144.                         GUILayout.Label(new GUIContent("Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    145.                     }
    146.                 }
    147.                 else
    148.                 {
    149.                     GUILayout.Label("Select a Prefab to replace objects with", EditorStyles.boldLabel);
    150.                 }
    151.                 #endregion
    152.  
    153.                 #region Draw Bottom Buttons
    154.                 GUILayout.Space(5);
    155.                 GUILayout.BeginHorizontal();
    156.                 {
    157.                     if (prefab != null && objectsToReplace.Count > 0)
    158.                     {
    159.                         if (GUILayout.Button("Apply"))
    160.                         {
    161.                             if (!keepOriginalNames)
    162.                             {
    163.                                 Rename();
    164.                             }
    165.                             foreach (GameObject go in objectsToReplace)
    166.                             {
    167.                                 Replace(go);
    168.                                 DestroyImmediate(go);
    169.                             }
    170.                             editMode = false;
    171.                             EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // Important so that we don't forget to save!
    172.                         }
    173.                         else if (GUILayout.Button("Cancel"))
    174.                         {
    175.                             ResetPreview();
    176.                             editMode = false;
    177.                         }
    178.                     }
    179.                 }
    180.                 GUILayout.EndHorizontal();
    181.                 #endregion
    182.             }
    183.             else
    184.             {
    185.                 objectsToReplace.Clear();
    186.                 tempObjects.Clear();
    187.                 prefab = null;
    188.             }
    189.         }
    190.  
    191.         /// <summary>
    192.         /// Renames the gameObjects, adding numbering following the default Unity naming convention i.e. "Cube (1)".
    193.         /// It checks for already used numbers.
    194.         /// Finds the "space" character in the name to identify where the number is, then strips the brackets.
    195.         /// </summary>
    196.         void Rename()
    197.         {
    198.             int count = 0;
    199.             List<int> ExistingNumbers = new List<int>();
    200.  
    201.             foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
    202.             {
    203.                 if (obj.name.Contains(prefab.name))
    204.                 {
    205.                     string[] stringSplit = obj.name.Split(' '); // number deliminator, setup for default Unity naming convention i.e "Cube (1)"
    206.                     if (stringSplit.Length > 1)
    207.                     {
    208.                         char[] charsToTrim = { '(', ')' }; // extra characters to trim
    209.                         string num = stringSplit[1].Trim(charsToTrim); // substring which contains number
    210.                         int x = int.Parse(num); // convert string to number
    211.                         ExistingNumbers.Add(x);
    212.                     }
    213.                 }
    214.             }
    215.  
    216.             foreach (GameObject go in tempObjects)
    217.             {
    218.                 count++;
    219.                 if (ExistingNumbers.Count > 0)
    220.                 {
    221.                     int i = 0;
    222.                     while (i < (ExistingNumbers.Count))
    223.                     {
    224.                         if (count == (ExistingNumbers[i]))
    225.                         {
    226.                             count++;
    227.                             i = 0;
    228.                         }
    229.                         else
    230.                         {
    231.                             i++;
    232.                         }
    233.                     }
    234.                 }
    235.                 go.transform.name = go.transform.name + " (" + count + ")";
    236.             }
    237.         }
    238.  
    239.         /// <summary>
    240.         /// Replaces a given gameObject with a previously chosen prefab.
    241.         /// </summary>
    242.         /// <param name="obj">The gameObject to replace.</param>
    243.         void Replace(GameObject obj)
    244.         {
    245.             GameObject newObject;
    246.  
    247.         #if UNITY_2018_2_OR_NEWER
    248.             newObject = PrefabUtility.InstantiatePrefab(PrefabUtility.GetCorrespondingObjectFromSource(prefab)) as GameObject;
    249.         #else
    250.             newObject = PrefabUtility.InstantiatePrefab(PrefabUtility.GetPrefabParent(prefab)) as GameObject;
    251.         #endif
    252.  
    253.             if (newObject == null) // if the prefab is chosen from the project browser and not the hierarchy, it is null
    254.             {
    255.                 newObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
    256.             }
    257.  
    258.             newObject.transform.SetParent(obj.transform.parent, true);
    259.            
    260.             newObject.transform.localPosition = obj.transform.localPosition;
    261.  
    262.             if (applyRotation)
    263.             {
    264.                 newObject.transform.localRotation = obj.transform.localRotation;
    265.             }
    266.  
    267.             if (applyScale)
    268.             {
    269.                 newObject.transform.localScale = obj.transform.localScale;
    270.             }
    271.  
    272.             tempObjects.Add(newObject);
    273.  
    274.             if (keepOriginalNames)
    275.             {
    276.                 newObject.transform.name = obj.transform.name;
    277.             }
    278.  
    279.             if (keepPlaceInHierarchy)
    280.             {
    281.                 newObject.transform.SetSiblingIndex(obj.transform.GetSiblingIndex());
    282.             }
    283.  
    284.             Undo.RegisterCreatedObjectUndo(newObject, "Replaced Objects");
    285.             Undo.DestroyObjectImmediate(obj);
    286.         }
    287.  
    288.         /// <summary>
    289.         /// Gets the currently selected game objects.
    290.         /// </summary>
    291.         void GetSelection()
    292.         {
    293.             if (editMode && Selection.activeGameObject != null)
    294.             {
    295.                 if (prefab == null) // get the prefab 1st
    296.                 {
    297.                 #if UNITY_2018_3_OR_NEWER
    298.                     PrefabAssetType t = PrefabUtility.GetPrefabAssetType(Selection.activeGameObject);
    299.  
    300.                     if (t == PrefabAssetType.Regular || t == PrefabAssetType.Variant)
    301.                     {
    302.                         prefab = Selection.activeGameObject;
    303.                     }
    304.                 #else
    305.                     PrefabType t = PrefabUtility.GetPrefabType(Selection.activeGameObject);
    306.  
    307.                     if (t == PrefabType.Prefab)
    308.                     {
    309.                         prefab = Selection.activeGameObject;
    310.                     }
    311.                 #endif
    312.                 }
    313.                 else // get the other objects
    314.                 {
    315.                     ResetPreview();
    316.                     objectsToReplace.Clear();
    317.                     foreach (var obj in Selection.gameObjects)
    318.                     {
    319.                         objectsToReplace.Add(obj);
    320.                     }
    321.                 }
    322.             }
    323.         }
    324.  
    325.         /// <summary>
    326.         /// Resets the gameObject preview.
    327.         /// </summary>
    328.         void ResetPreview()
    329.         {
    330.             if (tempObjects != null)
    331.             {
    332.                 foreach (GameObject go in tempObjects)
    333.                 {
    334.                     DestroyImmediate(go);
    335.                 }
    336.             }
    337.             tempObjects.Clear();
    338.         }
    339.  
    340.         /// <summary>
    341.         /// Handles window destruction.
    342.         /// </summary>
    343.         void OnDestroy()
    344.         {
    345.             ResetPreview();
    346.         }
    347.  
    348.         /// <summary>
    349.         /// Compares the names of two objects ignoring case and returns a signed int (-1 for less than, 0  equals, 1 for greater than).
    350.         /// </summary>
    351.         /// <param name="a">The first object to compare</param>
    352.         /// <param name="b">The second object to compare</param>
    353.         /// <returns></returns>
    354.         int NameCompare(Object a, Object b)
    355.         {
    356.             return new CaseInsensitiveComparer().Compare(a.name, b.name);
    357.         }
    358.     }
    359. }
     
    Last edited: Mar 22, 2020
    sssooonnnggg and williammotta like this.
  35. gghitman69

    gghitman69

    Joined:
    Mar 4, 2016
    Posts:
    93
    hello I have taken the script that is great
    I have added search by tag or layer
    the object will replace the tag and the layer of the original object
    compare and exchange materials
    I'm beginning if someone wants to correct

    Code (CSharp):
    1. /*=================== Replace with Prefab ===================
    2. Unity Forum Community Thread https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    3. Tested in 2018.4.19f1, 2019.3.6f1
    4. Should work in pre-2018.3 versions with old prefab workflow (Needs testing)
    5. Changelog and contributors:
    6. v1.0.0 (2010-03) Original CopyComponents by Michael L. Croswell for Colorado Game Coders, LLC
    7. v1.1.0 (2011-06) by Kristian Helle Jespersen
    8. v1.2.0 (2015-04) by Connor Cadellin McKee for Excamedia
    9. v1.3.0 (2015-04) by Fernando Medina (fermmmm)
    10. v1.4.0 (2015-07) by Julien Tonsuso (www.julientonsuso.com)
    11. v1.5.0 (2017-06) by Alex Dovgodko
    12.                  Changed into editor window and added instant preview in scene view
    13. v1.6.0 (2018-03) by ???
    14.                  Made changes to make things work with Unity 5.6.1
    15. v1.7.0 (2018-05) by Carlos Diosdado (hypertectonic)
    16.                  Added link to community thread, booleans to choose if scale and rotation are applied, mark scene as dirty, changed menu item
    17. v1.8.0 (2018-??) by Virgil Iordan
    18.                  Added KeepPlaceInHierarchy
    19. v1.9.0 (2019-01) by Dev Bye-A-Jee, Sanjay Sen & Nick Rodriguez for Ravensbourne University London
    20.                  Added unique numbering identifier in the hierarchy to each newly instantiated prefab, also accounts for existing numbers
    21. v2.0.0 (2020-03-22) by Zan Kievit
    22.                     Made compatible with the new Prefab system of Unity 2018. Made more user friendly and added undo.
    23. v2.1.0 (2020-03-22) by Carlos Diosdado (hypertectonic)
    24.                     Added options to use as a utility window (show from right click in the hierarchy), min/max window size,
    25.                     backwards compatibility for old prefab system, works with prefabs selected in project browser, fixed not replacing prefabs,
    26.                     added version numbers, basic documentation, Community namespace to avoid conflicts, cleaned up code for readability.
    27. v2.2.0 (2020-03-22) by GGHitman
    28.                     Add Search by tag or by layer
    29.                     the object will replace the tag and the layer of the original object
    30.                     compare and exchange materials
    31.  
    32. Known Errors: Rename - numbering doesn't work (since?)
    33.               Rename - throws error when prefab has multiple spaces in their name
    34. ============================================================*/
    35.  
    36. using UnityEngine;
    37. using UnityEditor;
    38. using UnityEditor.SceneManagement;
    39. using System.Collections;
    40. using System.Collections.Generic;
    41.  
    42. namespace Community
    43. {
    44.     /// <summary>
    45.     /// An editor tool to replace selected GameObjects with a specified Prefab.
    46.     /// </summary>
    47.     public class ReplaceWithPrefab : EditorWindow
    48.     {
    49.         public GameObject prefab = null;
    50.         public List<GameObject> objectsToReplace = new List<GameObject>();
    51.         public List<GameObject> tempObjects = new List<GameObject>();
    52.         public bool editMode = false;
    53.         public bool keepOriginalNames = false;
    54.         public bool applyRotation = true;
    55.         public bool applyScale = true;
    56.         public bool keepPlaceInHierarchy = true;
    57.  
    58.         public bool SearchWithTag = false;
    59.         public string TagForSearch;
    60.         public GameObject[] searchResult;
    61.  
    62.         public bool SearchWithLayer = false;
    63.         public int LayerForSearch;
    64.  
    65.  
    66.         private Vector2 windowMinSize = new Vector2(450, 300);
    67.         private Vector2 windowMaxSize = new Vector2(800, 1000);
    68.         private Vector2 scrollPosition;
    69.  
    70.         /// <summary>
    71.         /// Gets or creates a new Replace with Prefab window.
    72.         /// </summary>
    73.         [MenuItem("Tools/Community/Replace with Prefabaaaaaa")]
    74.         static void StartWindow()
    75.         {
    76.             ReplaceWithPrefab window = (ReplaceWithPrefab)GetWindow(typeof(ReplaceWithPrefab));
    77.             window.Show();
    78.  
    79.             window.titleContent = new GUIContent("Replace with Prefab");
    80.             window.minSize = window.windowMinSize;
    81.             window.maxSize = window.windowMaxSize;
    82.         }
    83.  
    84.         /// <summary>
    85.         /// Handles getting the selected objects when the selection changes.
    86.         /// </summary>
    87.         void OnSelectionChange()
    88.         {
    89.             GetSelection();
    90.             Repaint();
    91.         }
    92.  
    93.         /// <summary>
    94.         /// Draws the window content: object list, configuration and execution buttons.
    95.         /// </summary>
    96.         void OnGUI()
    97.         {
    98.             #region Draw Top Buttons
    99.  
    100.             GUILayout.BeginHorizontal(EditorStyles.toolbar);
    101.             {
    102.                 editMode = GUILayout.Toggle(editMode, new GUIContent("Edit", "Start using this feature"), EditorStyles.toggle);
    103.                 GUILayout.FlexibleSpace();
    104.  
    105.             }
    106.             GUILayout.EndHorizontal();
    107.             #endregion
    108.  
    109.             keepOriginalNames = GUILayout.Toggle(keepOriginalNames, "Keep names", EditorStyles.toggle);
    110.             applyRotation = GUILayout.Toggle(applyRotation, "Apply rotation", EditorStyles.toggle);
    111.             applyScale = GUILayout.Toggle(applyScale, "Apply scale", EditorStyles.toggle);
    112.             keepPlaceInHierarchy = GUILayout.Toggle(keepPlaceInHierarchy, "Keep Place In Hierarchy", EditorStyles.toggle);
    113.  
    114.             #region "TAG LAYER"
    115.  
    116.             SearchWithTag = GUILayout.Toggle(SearchWithTag, "Apply Search By Tag", EditorStyles.toggle);
    117.             SearchWithLayer = GUILayout.Toggle(SearchWithLayer, "Apply Search By Layer");
    118.             //if(SearchWithTag)
    119.             //{
    120.             //    TagForSearch = EditorGUILayout.TagField(TagForSearch);
    121.             //}
    122.  
    123.             if (SearchWithTag)
    124.             {
    125.  
    126.                 GUILayout.Space(5);
    127.                 TagForSearch = EditorGUILayout.TagField("Set tag :  ", TagForSearch);
    128.  
    129.              
    130.             }
    131.  
    132.             if (SearchWithLayer)
    133.             {
    134.                 GUILayout.Space(5);
    135.                 LayerForSearch = EditorGUILayout.LayerField("Set layer :  ", LayerForSearch);
    136.  
    137.              
    138.             }
    139.             #endregion "TAG LAYER"
    140.  
    141.  
    142.  
    143.             if (GUI.changed)
    144.             {
    145.                 if (editMode)
    146.                     GetSelection();
    147.                 else
    148.                     ResetPreview();
    149.             }
    150.  
    151.             GUILayout.Space(5);
    152.             if (editMode)
    153.             {
    154.                 ResetPreview();
    155.  
    156.                 #region Draw Prefab and List
    157.  
    158.                 if (prefab != null)
    159.                 {
    160.                     GUILayout.Label("Prefab: ", EditorStyles.boldLabel);
    161.                     GUILayout.Label(prefab.name);
    162.                     GUILayout.Space(10);
    163.  
    164.                     if (objectsToReplace.Count > 0)
    165.                     {
    166.                         GUILayout.Label(new GUIContent("Objects to be Replaced:", "Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    167.                         objectsToReplace.Sort(NameCompare);
    168.  
    169.                         scrollPosition = GUILayout.BeginScrollView(scrollPosition, EditorStyles.helpBox);
    170.                         {
    171.                             foreach (GameObject go in objectsToReplace)
    172.                             {
    173.                                 GUILayout.BeginHorizontal(EditorStyles.toolbar);
    174.                                 GUILayout.Label(go.name);
    175.                                 GUILayout.EndHorizontal();
    176.                             }
    177.                             GUILayout.Space(2);
    178.                         }
    179.                         GUILayout.EndScrollView();
    180.                     }
    181.                     else
    182.                     {
    183.                         GUILayout.Label(new GUIContent("Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    184.                     }
    185.                 }
    186.                 else
    187.                 {
    188.                     GUILayout.Label("Select a Prefab to replace objects with", EditorStyles.boldLabel);
    189.                 }
    190.                 #endregion
    191.  
    192.                 #region Draw Bottom Buttons
    193.  
    194.                 GUILayout.Space(5);
    195.                 GUILayout.BeginHorizontal();
    196.                 {
    197.                     if (prefab != null && objectsToReplace.Count > 0)
    198.                     {
    199.                         if (GUILayout.Button("Apply"))
    200.                         {
    201.  
    202.                             if (!keepOriginalNames)
    203.                             {
    204.                                 Rename();
    205.                             }
    206.                             foreach (GameObject go in objectsToReplace)
    207.                             {
    208.                                 Replace(go);
    209.                                 DestroyImmediate(go);
    210.                             }
    211.                             editMode = false;
    212.                             EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // Important so that we don't forget to save!
    213.  
    214.  
    215.                         }
    216.                         else if (GUILayout.Button("Cancel"))
    217.                         {
    218.                             ResetPreview();
    219.                             editMode = false;
    220.  
    221.                         }
    222.                     }
    223.                 }
    224.                 GUILayout.EndHorizontal();
    225.  
    226.                 #endregion
    227.             }
    228.             else
    229.             {
    230.                 objectsToReplace.Clear();
    231.                 tempObjects.Clear();
    232.                 prefab = null;
    233.  
    234.             }
    235.         }
    236.  
    237.         /// <summary>
    238.         /// Renames the gameObjects, adding numbering following the default Unity naming convention i.e. "Cube (1)".
    239.         /// It checks for already used numbers.
    240.         /// Finds the "space" character in the name to identify where the number is, then strips the brackets.
    241.         /// </summary>
    242.         void Rename()
    243.         {
    244.             int count = 0;
    245.             List<int> ExistingNumbers = new List<int>();
    246.  
    247.             foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
    248.             {
    249.                 if (obj.name.Contains(prefab.name))
    250.                 {
    251.                     string[] stringSplit = obj.name.Split(' '); // number deliminator, setup for default Unity naming convention i.e "Cube (1)"
    252.                     if (stringSplit.Length > 1)
    253.                     {
    254.                         char[] charsToTrim = { '(', ')' }; // extra characters to trim
    255.                         string num = stringSplit[1].Trim(charsToTrim); // substring which contains number
    256.                         int x = int.Parse(num); // convert string to number
    257.                         ExistingNumbers.Add(x);
    258.                     }
    259.                 }
    260.             }
    261.  
    262.             foreach (GameObject go in tempObjects)
    263.             {
    264.                 count++;
    265.                 if (ExistingNumbers.Count > 0)
    266.                 {
    267.                     int i = 0;
    268.                     while (i < (ExistingNumbers.Count))
    269.                     {
    270.                         if (count == (ExistingNumbers[i]))
    271.                         {
    272.                             count++;
    273.                             i = 0;
    274.                         }
    275.                         else
    276.                         {
    277.                             i++;
    278.                         }
    279.                     }
    280.                 }
    281.                 go.transform.name = go.transform.name + " (" + count + ")";
    282.             }
    283.         }
    284.  
    285.         /// <summary>
    286.         /// Replaces a given gameObject with a previously chosen prefab.
    287.         /// </summary>
    288.         /// <param name="obj">The gameObject to replace.</param>
    289.         void Replace(GameObject obj)
    290.         {
    291.             GameObject newObject;
    292.  
    293.  
    294.             newObject = PrefabUtility.InstantiatePrefab(PrefabUtility.GetCorrespondingObjectFromSource(prefab)) as GameObject;
    295.  
    296.  
    297.             if (newObject == null) // if the prefab is chosen from the project browser and not the hierarchy, it is null
    298.             {
    299.                 newObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
    300.             }
    301.  
    302.             newObject.transform.SetParent(obj.transform.parent, true);
    303.  
    304.             newObject.transform.localPosition = obj.transform.localPosition;
    305.  
    306.             if (applyRotation)
    307.             {
    308.                 newObject.transform.localRotation = obj.transform.localRotation;
    309.             }
    310.  
    311.             if (applyScale)
    312.             {
    313.                 newObject.transform.localScale = obj.transform.localScale;
    314.             }
    315.  
    316.             tempObjects.Add(newObject);
    317.  
    318.             if (keepOriginalNames)
    319.             {
    320.                 newObject.transform.name = obj.transform.name;
    321.             }
    322.  
    323.             if (keepPlaceInHierarchy)
    324.             {
    325.                 newObject.transform.SetSiblingIndex(obj.transform.GetSiblingIndex());
    326.             }
    327.  
    328.             newObject.gameObject.tag = obj.tag;
    329.             newObject.gameObject.layer = obj.layer;
    330.  
    331.             if (obj.GetComponent<MeshRenderer>())
    332.             {
    333.                 if (newObject.GetComponent<MeshRenderer>())
    334.                 {
    335.                     if (obj.GetComponent<MeshRenderer>().sharedMaterials.Length == newObject.GetComponent<MeshRenderer>().sharedMaterials.Length)
    336.                     {
    337.                         Material[] CacheMaterials = new Material[obj.GetComponent<MeshRenderer>().sharedMaterials.Length];
    338.                         for (int a = 0; a < obj.GetComponent<MeshRenderer>().sharedMaterials.Length; a++)
    339.                         {
    340.                             CacheMaterials[a] = obj.GetComponent<MeshRenderer>().sharedMaterials[a];
    341.                         }
    342.                         for (int b = 0; b < CacheMaterials.Length; b++)
    343.                         {
    344.                             newObject.GetComponent<MeshRenderer>().sharedMaterials[b] = CacheMaterials[b];
    345.                         }
    346.  
    347.                     }
    348.                 }
    349.  
    350.             }
    351.  
    352.             if (obj.GetComponent<SkinnedMeshRenderer>())
    353.             {
    354.                 if (newObject.GetComponent<SkinnedMeshRenderer>())
    355.                 {
    356.                     if (obj.GetComponent<SkinnedMeshRenderer>().sharedMaterials.Length == newObject.GetComponent<SkinnedMeshRenderer>().sharedMaterials.Length)
    357.                     {
    358.                         Material[] CacheMaterials = new Material[obj.GetComponent<SkinnedMeshRenderer>().sharedMaterials.Length];
    359.                         for (int a = 0; a < obj.GetComponent<SkinnedMeshRenderer>().sharedMaterials.Length; a++)
    360.                         {
    361.                             CacheMaterials[a] = obj.GetComponent<SkinnedMeshRenderer>().sharedMaterials[a];
    362.                         }
    363.                         for (int b = 0; b < CacheMaterials.Length; b++)
    364.                         {
    365.                             newObject.GetComponent<SkinnedMeshRenderer>().sharedMaterials[b] = CacheMaterials[b];
    366.                         }
    367.  
    368.                     }
    369.                 }
    370.  
    371.             }
    372.  
    373.             Undo.RegisterCreatedObjectUndo(newObject, "Replaced Objects");
    374.             Undo.DestroyObjectImmediate(obj);
    375.         }
    376.  
    377.         /// <summary>
    378.         /// Gets the currently selected game objects.
    379.         /// </summary>
    380.         void GetSelection()
    381.         {
    382.             if (editMode && Selection.activeGameObject != null)
    383.             {
    384.                 if (prefab == null) // get the prefab 1st
    385.                 {
    386.                     PrefabAssetType t = PrefabUtility.GetPrefabAssetType(Selection.activeGameObject);
    387.  
    388.                     if (t == PrefabAssetType.Regular || t == PrefabAssetType.Variant)
    389.                     {
    390.                         prefab = Selection.activeGameObject;
    391.                     }
    392.  
    393.                 }
    394.                 else // get the other objects
    395.                 {
    396.                     if (SearchWithTag)
    397.                     {
    398.  
    399.                         ResetPreview();
    400.                         objectsToReplace.Clear();
    401.                         GameObject[] allGameObjects = GameObject.FindObjectsOfType<GameObject>();
    402.                         foreach (var gg in allGameObjects)
    403.                         {
    404.                             if (gg.tag == TagForSearch)
    405.                             {
    406.                                 objectsToReplace.Add(gg);
    407.                             }
    408.                         }
    409.  
    410.                     }
    411.                     else if (SearchWithLayer)
    412.                     {
    413.                         ResetPreview();
    414.                         objectsToReplace.Clear();
    415.                         GameObject[] allGameObjects = GameObject.FindObjectsOfType<GameObject>();
    416.                         foreach (var gg in allGameObjects)
    417.                         {
    418.                             if (gg.layer == LayerForSearch)
    419.                             {
    420.  
    421.                                 objectsToReplace.Add(gg);
    422.                             }
    423.                         }
    424.  
    425.  
    426.                     }
    427.                     else
    428.                     {
    429.                         ResetPreview();
    430.                         objectsToReplace.Clear();
    431.                         foreach (var obj in Selection.gameObjects)
    432.                         {
    433.                             objectsToReplace.Add(obj);
    434.                         }
    435.                     }
    436.  
    437.                 }
    438.             }
    439.         }
    440.  
    441.         /// <summary>
    442.         /// Resets the gameObject preview.
    443.         /// </summary>
    444.         void ResetPreview()
    445.         {
    446.             if (tempObjects != null)
    447.             {
    448.                 foreach (GameObject go in tempObjects)
    449.                 {
    450.                     DestroyImmediate(go);
    451.                 }
    452.             }
    453.             tempObjects.Clear();
    454.         }
    455.  
    456.         /// <summary>
    457.         /// Handles window destruction.
    458.         /// </summary>
    459.         void OnDestroy()
    460.         {
    461.             ResetPreview();
    462.         }
    463.  
    464.         /// <summary>
    465.         /// Compares the names of two objects ignoring case and returns a signed int (-1 for less than, 0  equals, 1 for greater than).
    466.         /// </summary>
    467.         /// <param name="a">The first object to compare</param>
    468.         /// <param name="b">The second object to compare</param>
    469.         /// <returns></returns>
    470.         int NameCompare(Object a, Object b)
    471.         {
    472.             return new CaseInsensitiveComparer().Compare(a.name, b.name);
    473.         }
    474.     }
    475. }
     
    Creepy-Cat likes this.
  36. SpaceRay

    SpaceRay

    Joined:
    Feb 26, 2014
    Posts:
    455
    Hello, I have just discovered this thread, and I think is really great, awesome, useful, helpful, time saving and lovely to be able to replace objects with the scripts, will be testing how it works and what can be done

    You can build a whole scene with many objects and then rebuild it with other objects keeping the same positions

    Thanks very much
     
  37. SkrenZz

    SkrenZz

    Joined:
    Apr 11, 2020
    Posts:
    26
    Just found this thread which saved me so much time and tedious work... Thank you all, you wonderful human-beings :D
     
    phobos2077 likes this.
  38. Wip3ou7

    Wip3ou7

    Joined:
    Mar 9, 2015
    Posts:
    41
    Does this script work with 2017? Also, alt-drag replacement works for me, but for some reason does not keep the transform position of the object I'm replacing, which makes it completely useless.
     
  39. signalsaudio

    signalsaudio

    Joined:
    Jul 13, 2019
    Posts:
    4
    Here's another script (that could be easily improved upon) to bulk replace prefabs with different identically named prefabs.

    Here's a video showing the usecase:



    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.IO;
    5.  
    6. public class BulkReplaceIdenticallyNamedPrefabs : EditorWindow
    7. {
    8.  
    9.     private SerializedObject serialized;
    10.  
    11.     private void OnEnable()
    12.     {
    13.         serialized = new SerializedObject(this);
    14.     }
    15.  
    16.     [MenuItem("Tools/Replace prefabs with new prefabs (identically named)")]
    17.  
    18.     static void CreateReplaceWithPrefab()
    19.     {
    20.         GetWindow<BulkReplaceIdenticallyNamedPrefabs>();
    21.     }
    22.  
    23.  
    24.     private void OnGUI()
    25.     {
    26.         if (GUILayout.Button("Select new prefab folder"))
    27.         {
    28.             ReplacePrefabs();
    29.         }
    30.     }
    31.  
    32.     private void ReplacePrefabs()
    33.     {
    34.         string newPrefabPath = EditorUtility.OpenFolderPanel("Select the folder with the new prefabs", "", "");
    35.         string[] newPrefabFilePaths = Directory.GetFiles(newPrefabPath);
    36.  
    37.         List<GameObject> newPrefabs = new List<GameObject>();
    38.  
    39.         newPrefabs = createListOfPrefabs(newPrefabFilePaths);
    40.  
    41.  
    42.         GameObject[] sceneGameObjects = FindObjectsOfType<GameObject>();
    43.  
    44.         List<GameObject> gameObjectsToDelete = new List<GameObject>();
    45.  
    46.  
    47.         foreach (GameObject newPrefab in newPrefabs)
    48.         {
    49.  
    50.             foreach (GameObject sceneGameObject in sceneGameObjects)
    51.             {
    52.                 if (sceneGameObject.name.Contains(newPrefab.name))
    53.                 {
    54.  
    55.  
    56.                     GameObject newPrefabInstantiation = (GameObject)PrefabUtility.InstantiatePrefab(newPrefab);
    57.                     Undo.RegisterCreatedObjectUndo(newPrefabInstantiation, "Replace Prefabs");
    58.  
    59.                     newPrefabInstantiation.transform.position = sceneGameObject.transform.position;
    60.                     newPrefabInstantiation.transform.rotation = sceneGameObject.transform.rotation;
    61.                     newPrefabInstantiation.transform.localScale = sceneGameObject.transform.localScale;
    62.                     newPrefabInstantiation.transform.parent = sceneGameObject.transform.parent;
    63.                     newPrefabInstantiation.transform.name = sceneGameObject.transform.name;
    64.                     newPrefabInstantiation.transform.SetSiblingIndex(sceneGameObject.transform.GetSiblingIndex());
    65.                     gameObjectsToDelete.Add(sceneGameObject);
    66.  
    67.                     Debug.Log("replaced " + sceneGameObject.name);
    68.                 }
    69.  
    70.             }
    71.  
    72.         }
    73.  
    74.         // Backwards loop for safe deletion
    75.         for (int i = gameObjectsToDelete.Count - 1; i >= 0; i--)
    76.         {
    77.             try
    78.             {
    79.                 DestroyImmediate(gameObjectsToDelete[i]);
    80.             }
    81.             catch
    82.             {
    83.                 Debug.Log("Couldn't delete" + gameObjectsToDelete[i].name);
    84.             }
    85.         }
    86.  
    87.     }
    88.  
    89.  
    90.     private List<GameObject> createListOfPrefabs(string[] filePaths)
    91.     {
    92.         List<GameObject> listOfPrefabs = new List<GameObject>();
    93.  
    94.         foreach (string filePath in filePaths)
    95.         {
    96.             try
    97.             {
    98.                 string relativeFilePath = "Assets" + filePath.Substring(Application.dataPath.Length);
    99.                 if (filePath.EndsWith(".prefab"))
    100.                 {
    101.                     GameObject loadedPrefab = (GameObject)AssetDatabase.LoadAssetAtPath(relativeFilePath, typeof(GameObject));
    102.                     listOfPrefabs.Add(loadedPrefab);
    103.                 }
    104.             }
    105.             catch
    106.             {
    107.                 Debug.Log("File or file path problem...");
    108.             }
    109.  
    110.         }
    111.         return listOfPrefabs;
    112.     }
    113. }
     
    Marc-Saubion likes this.
  40. jadeintheshade

    jadeintheshade

    Joined:
    Sep 29, 2020
    Posts:
    1
    I wanted something that would preserve any changes of the GameObjects that were being replaced with prefabs so that it could be used as a refactoring tool.

    Hmmm, perhaps whether it does that should be another checkbox.

    One thing it is lacking currently is the ability to properly hook back up internal references, e.g. if you have a sprite pointing at an image under the same branch of objects, it might turn into None or think it has a new default. I might take a stab at keeping a map of old objects to new objects and trying to update those properties to point to the new objects at some point.

    // Jade

    Code (CSharp):
    1. /*=================== Replace with Prefab ===================
    2. Unity Forum Community Thread https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    3. Tested in 2018.4.19f1, 2019.3.6f1
    4. Should work in pre-2018.3 versions with old prefab workflow (Needs testing)
    5. Changelog and contributors:
    6. v1.0.0 (2010-03) Original CopyComponents by Michael L. Croswell for Colorado Game Coders, LLC
    7. v1.1.0 (2011-06) by Kristian Helle Jespersen
    8. v1.2.0 (2015-04) by Connor Cadellin McKee for Excamedia
    9. v1.3.0 (2015-04) by Fernando Medina (fermmmm)
    10. v1.4.0 (2015-07) by Julien Tonsuso (www.julientonsuso.com)
    11. v1.5.0 (2017-06) by Alex Dovgodko
    12.                  Changed into editor window and added instant preview in scene view
    13. v1.6.0 (2018-03) by ???
    14.                  Made changes to make things work with Unity 5.6.1
    15. v1.7.0 (2018-05) by Carlos Diosdado (hypertectonic)
    16.                  Added link to community thread, booleans to choose if scale and rotation are applied, mark scene as dirty, changed menu item
    17. v1.8.0 (2018-??) by Virgil Iordan
    18.                  Added KeepPlaceInHierarchy
    19. v1.9.0 (2019-01) by Dev Bye-A-Jee, Sanjay Sen & Nick Rodriguez for Ravensbourne University London
    20.                  Added unique numbering identifier in the hierarchy to each newly instantiated prefab, also accounts for existing numbers
    21. v2.0.0 (2020-03-22) by Zan Kievit
    22.                     Made compatible with the new Prefab system of Unity 2018. Made more user friendly and added undo.
    23. v2.1.0 (2020-03-22) by Carlos Diosdado (hypertectonic)
    24.                     Added options to use as a utility window (show from right click in the hierarchy), min/max window size,
    25.                     backwards compatibility for old prefab system, works with prefabs selected in project browser, fixed not replacing prefabs,
    26.                     added version numbers, basic documentation, Community namespace to avoid conflicts, cleaned up code for readability.
    27. v2.2.0 (2020-03-22) by GGHitman
    28.                     Add Search by tag or by layer
    29.                     the object will replace the tag and the layer of the original object
    30.                     compare and exchange materials
    31. v.2.3.0 (2020-10-20) by Jade Annand
    32.                     Added recursive game object, component, field and value copying.
    33. Known Errors: Rename - numbering doesn't work (since?)
    34.               Rename - throws error when prefab has multiple spaces in their name
    35. ============================================================*/
    36.  
    37. using UnityEngine;
    38. using UnityEditor;
    39. using UnityEditor.SceneManagement;
    40. using System.Collections;
    41. using System.Collections.Generic;
    42.  
    43. namespace Community
    44. {
    45.     /// <summary>
    46.     /// An editor tool to replace selected GameObjects with a specified Prefab.
    47.     /// </summary>
    48.     public class ReplaceWithPrefab : EditorWindow
    49.     {
    50.         public GameObject prefab = null;
    51.         public List<GameObject> objectsToReplace = new List<GameObject>();
    52.         public List<GameObject> tempObjects = new List<GameObject>();
    53.         public bool editMode = false;
    54.  
    55.         public struct ReplacementPreferences
    56.         {
    57.             public bool keepOriginalNames;
    58.             public bool applyRotation;
    59.             public bool applyScale;
    60.             public bool keepPlaceInHierarchy;
    61.         }
    62.  
    63.         public ReplacementPreferences replacementPreferences;
    64.  
    65.         public bool SearchWithTag = false;
    66.         public string TagForSearch;
    67.         public GameObject[] searchResult;
    68.  
    69.         public bool SearchWithLayer = false;
    70.         public int LayerForSearch;
    71.  
    72.  
    73.         private Vector2 windowMinSize = new Vector2(450, 300);
    74.         private Vector2 windowMaxSize = new Vector2(800, 1000);
    75.         private Vector2 scrollPosition;
    76.  
    77.         private static readonly IDictionary<System.Type, IComponentCopier> componentCopiers = new Dictionary<System.Type, IComponentCopier>();
    78.         private static readonly IDictionary<System.Type, ISet<string>> componentPartAvoiders = new Dictionary<System.Type, ISet<string>>();
    79.  
    80.         static ReplaceWithPrefab()
    81.         {
    82.             RegisterComponentCopiers();
    83.             RegisterComponentPartAvoiders();
    84.         }
    85.  
    86.         /// <summary>
    87.         /// Gets or creates a new Replace with Prefab window.
    88.         /// </summary>
    89.         [MenuItem("Tools/Community/Replace with Prefab")]
    90.         static void StartWindow()
    91.         {
    92.             ReplaceWithPrefab window = (ReplaceWithPrefab)GetWindow(typeof(ReplaceWithPrefab));
    93.             window.Show();
    94.  
    95.             window.titleContent = new GUIContent("Replace with Prefab");
    96.             window.minSize = window.windowMinSize;
    97.             window.maxSize = window.windowMaxSize;
    98.         }
    99.  
    100.         public ReplaceWithPrefab()
    101.         {
    102.             replacementPreferences.keepOriginalNames = true;
    103.             replacementPreferences.applyRotation = true;
    104.             replacementPreferences.applyScale = true;
    105.             replacementPreferences.keepPlaceInHierarchy = true;
    106.         }
    107.  
    108.         /// <summary>
    109.         /// Handles getting the selected objects when the selection changes.
    110.         /// </summary>
    111.         void OnSelectionChange()
    112.         {
    113.             GetSelection();
    114.             Repaint();
    115.         }
    116.  
    117.         /// <summary>
    118.         /// Draws the window content: object list, configuration and execution buttons.
    119.         /// </summary>
    120.         void OnGUI()
    121.         {
    122.             #region Draw Top Buttons
    123.  
    124.             GUILayout.BeginHorizontal(EditorStyles.toolbar);
    125.             {
    126.                 editMode = GUILayout.Toggle(editMode, new GUIContent("Start replacing", "Start using this feature"), EditorStyles.toggle);
    127.                 GUILayout.FlexibleSpace();
    128.  
    129.             }
    130.             GUILayout.EndHorizontal();
    131.             #endregion
    132.  
    133.             replacementPreferences.keepOriginalNames = GUILayout.Toggle(replacementPreferences.keepOriginalNames, "Keep names", EditorStyles.toggle);
    134.             replacementPreferences.applyRotation = GUILayout.Toggle(replacementPreferences.applyRotation, "Apply rotation", EditorStyles.toggle);
    135.             replacementPreferences.applyScale = GUILayout.Toggle(replacementPreferences.applyScale, "Apply scale", EditorStyles.toggle);
    136.             replacementPreferences.keepPlaceInHierarchy = GUILayout.Toggle(replacementPreferences.keepPlaceInHierarchy, "Keep place in hierarchy", EditorStyles.toggle);
    137.  
    138.             #region "TAG LAYER"
    139.  
    140.             SearchWithTag = GUILayout.Toggle(SearchWithTag, "Apply Search By Tag", EditorStyles.toggle);
    141.             SearchWithLayer = GUILayout.Toggle(SearchWithLayer, "Apply Search By Layer");
    142.             //if(SearchWithTag)
    143.             //{
    144.             //    TagForSearch = EditorGUILayout.TagField(TagForSearch);
    145.             //}
    146.  
    147.             if (SearchWithTag)
    148.             {
    149.  
    150.                 GUILayout.Space(5);
    151.                 TagForSearch = EditorGUILayout.TagField("Set tag :  ", TagForSearch);
    152.  
    153.  
    154.             }
    155.  
    156.             if (SearchWithLayer)
    157.             {
    158.                 GUILayout.Space(5);
    159.                 LayerForSearch = EditorGUILayout.LayerField("Set layer :  ", LayerForSearch);
    160.  
    161.  
    162.             }
    163.             #endregion "TAG LAYER"
    164.  
    165.             if (GUI.changed)
    166.             {
    167.                 if (editMode)
    168.                     GetSelection();
    169.                 else
    170.                     ResetPreview();
    171.             }
    172.  
    173.             GUILayout.Space(5);
    174.             if (editMode)
    175.             {
    176.                 ResetPreview();
    177.  
    178.                 #region Draw Prefab and List
    179.  
    180.                 if (prefab != null)
    181.                 {
    182.                     GUILayout.Label("Prefab: ", EditorStyles.boldLabel);
    183.                     GUILayout.Label(prefab.name);
    184.                     GUILayout.Space(10);
    185.  
    186.                     if (objectsToReplace.Count > 0)
    187.                     {
    188.                         GUILayout.Label(new GUIContent("Objects to be Replaced:", "Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    189.                         objectsToReplace.Sort(NameCompare);
    190.  
    191.                         scrollPosition = GUILayout.BeginScrollView(scrollPosition, EditorStyles.helpBox);
    192.                         {
    193.                             foreach (GameObject go in objectsToReplace)
    194.                             {
    195.                                 GUILayout.BeginHorizontal(EditorStyles.toolbar);
    196.                                 GUILayout.Label(go.name);
    197.                                 GUILayout.EndHorizontal();
    198.                             }
    199.                             GUILayout.Space(2);
    200.                         }
    201.                         GUILayout.EndScrollView();
    202.                     }
    203.                     else
    204.                     {
    205.                         GUILayout.Label(new GUIContent("Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    206.                     }
    207.                 }
    208.                 else
    209.                 {
    210.                     GUILayout.Label("Select a Prefab to replace objects with", EditorStyles.boldLabel);
    211.                 }
    212.                 #endregion
    213.  
    214.                 #region Draw Bottom Buttons
    215.  
    216.                 GUILayout.Space(5);
    217.                 GUILayout.BeginHorizontal();
    218.                 {
    219.                     if (prefab != null && objectsToReplace.Count > 0)
    220.                     {
    221.                         if (GUILayout.Button("Apply"))
    222.                         {
    223.  
    224.                             if (!replacementPreferences.keepOriginalNames)
    225.                             {
    226.                                 Rename();
    227.                             }
    228.                             foreach (GameObject go in objectsToReplace)
    229.                             {
    230.                                 Replace(go);
    231.                                 DestroyImmediate(go);
    232.                             }
    233.                             editMode = false;
    234.                             EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // Important so that we don't forget to save!
    235.                         }
    236.                         else if (GUILayout.Button("Cancel"))
    237.                         {
    238.                             ResetPreview();
    239.                             editMode = false;
    240.                         }
    241.                     }
    242.                 }
    243.                 GUILayout.EndHorizontal();
    244.                 #endregion
    245.             }
    246.             else
    247.             {
    248.                 objectsToReplace.Clear();
    249.                 tempObjects.Clear();
    250.                 prefab = null;
    251.             }
    252.         }
    253.  
    254.         /// <summary>
    255.         /// Renames the gameObjects, adding numbering following the default Unity naming convention i.e. "Cube (1)".
    256.         /// It checks for already used numbers.
    257.         /// Finds the "space" character in the name to identify where the number is, then strips the brackets.
    258.         /// </summary>
    259.         void Rename()
    260.         {
    261.             int count = 0;
    262.             List<int> ExistingNumbers = new List<int>();
    263.  
    264.             foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
    265.             {
    266.                 if (obj.name.Contains(prefab.name))
    267.                 {
    268.                     string[] stringSplit = obj.name.Split(' '); // number deliminator, setup for default Unity naming convention i.e "Cube (1)"
    269.                     if (stringSplit.Length > 1)
    270.                     {
    271.                         char[] charsToTrim = { '(', ')' }; // extra characters to trim
    272.                         string num = stringSplit[1].Trim(charsToTrim); // substring which contains number
    273.                         int x = int.Parse(num); // convert string to number
    274.                         ExistingNumbers.Add(x);
    275.                     }
    276.                 }
    277.             }
    278.  
    279.             foreach (GameObject go in tempObjects)
    280.             {
    281.                 count++;
    282.                 if (ExistingNumbers.Count > 0)
    283.                 {
    284.                     int i = 0;
    285.                     while (i < ExistingNumbers.Count)
    286.                     {
    287.                         if (count == ExistingNumbers[i])
    288.                         {
    289.                             count++;
    290.                             i = 0;
    291.                         }
    292.                         else
    293.                             i++;
    294.                     }
    295.                 }
    296.                 go.transform.name = go.transform.name + " (" + count + ")";
    297.             }
    298.         }
    299.  
    300.         /// <summary>
    301.         /// Replaces a given gameObject with a previously chosen prefab.
    302.         /// </summary>
    303.         /// <param name="obj">The gameObject to replace.</param>
    304.         void Replace(GameObject obj)
    305.         {
    306.             GameObject newObject;
    307.  
    308.             newObject = PrefabUtility.InstantiatePrefab(PrefabUtility.GetCorrespondingObjectFromSource(prefab)) as GameObject;
    309.  
    310.             if (newObject == null) // if the prefab is chosen from the project browser and not the hierarchy, it is null
    311.                 newObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
    312.  
    313.             newObject.transform.SetParent(obj.transform.parent, true);
    314.  
    315.             tempObjects.Add(newObject);
    316.  
    317.             CopyContentsToNew(obj, newObject);
    318.  
    319.             Undo.RegisterCreatedObjectUndo(newObject, "Replaced Objects");
    320.             Undo.DestroyObjectImmediate(obj);
    321.         }
    322.  
    323.         private void CopyContentsToNew(GameObject oldObject, GameObject newObject)
    324.         {
    325.             newObject.tag = oldObject.tag;
    326.             newObject.layer = oldObject.layer;
    327.  
    328.             Component[] components = oldObject.GetComponents(typeof(Component));
    329.             foreach (Component component in components)
    330.             {
    331.                 IComponentCopier copier = null;
    332.                 System.Type componentType = component.GetType();
    333.                 while (copier == null)
    334.                 {
    335.                     if (componentCopiers.ContainsKey(componentType))
    336.                         copier = componentCopiers[componentType];
    337.                     else if (componentType.BaseType == typeof(System.Object) ||
    338.                         componentType.BaseType == null)
    339.                         copier = defaultComponentCopier;
    340.                     else
    341.                         componentType = componentType.BaseType; // Components may be derivatives, so look up the tree.
    342.                 }
    343.                 copier.CopyComponent(replacementPreferences, component, newObject);
    344.             }
    345.             int childCount = oldObject.transform.childCount;
    346.             for (int i = 0; i < oldObject.transform.childCount; i++)
    347.             {
    348.                 GameObject child = oldObject.transform.GetChild(i).gameObject;
    349.                 GameObject newChild;
    350.                 Transform newChildTransform = newObject.transform.Find(child.name);
    351.                 if (newChildTransform == null)
    352.                 {
    353.                     newChild = new GameObject(child.name);
    354.                     newChild.transform.SetParent(newObject.transform, false);
    355.                 }
    356.                 else
    357.                     newChild = newChildTransform.gameObject;
    358.                 CopyContentsToNew(child, newChild);
    359.             }
    360.         }
    361.  
    362.         /// <summary>
    363.         /// Gets the currently selected game objects.
    364.         /// </summary>
    365.         void GetSelection()
    366.         {
    367.             if (editMode && Selection.activeGameObject != null)
    368.             {
    369.                 if (prefab == null) // get the prefab 1st
    370.                 {
    371.                     PrefabAssetType t = PrefabUtility.GetPrefabAssetType(Selection.activeGameObject);
    372.  
    373.                     if (t == PrefabAssetType.Regular || t == PrefabAssetType.Variant)
    374.                     {
    375.                         prefab = Selection.activeGameObject;
    376.                     }
    377.  
    378.                 }
    379.                 else // get the other objects
    380.                 {
    381.                     if (SearchWithTag)
    382.                     {
    383.                         ResetPreview();
    384.                         objectsToReplace.Clear();
    385.                         GameObject[] allGameObjects = GameObject.FindObjectsOfType<GameObject>();
    386.                         foreach (var gg in allGameObjects)
    387.                         {
    388.                             if (gg.tag == TagForSearch)
    389.                             {
    390.                                 objectsToReplace.Add(gg);
    391.                             }
    392.                         }
    393.                     }
    394.                     else if (SearchWithLayer)
    395.                     {
    396.                         ResetPreview();
    397.                         objectsToReplace.Clear();
    398.                         GameObject[] allGameObjects = GameObject.FindObjectsOfType<GameObject>();
    399.                         foreach (var gg in allGameObjects)
    400.                         {
    401.                             if (gg.layer == LayerForSearch)
    402.                             {
    403.                                 objectsToReplace.Add(gg);
    404.                             }
    405.                         }
    406.                     }
    407.                     else
    408.                     {
    409.                         ResetPreview();
    410.                         objectsToReplace.Clear();
    411.                         foreach (var obj in Selection.gameObjects)
    412.                         {
    413.                             objectsToReplace.Add(obj);
    414.                         }
    415.                     }
    416.                 }
    417.             }
    418.         }
    419.  
    420.         /// <summary>
    421.         /// Resets the gameObject preview.
    422.         /// </summary>
    423.         void ResetPreview()
    424.         {
    425.             if (tempObjects != null)
    426.             {
    427.                 foreach (GameObject go in tempObjects)
    428.                 {
    429.                     DestroyImmediate(go);
    430.                 }
    431.             }
    432.             tempObjects.Clear();
    433.         }
    434.  
    435.         /// <summary>
    436.         /// Handles window destruction.
    437.         /// </summary>
    438.         void OnDestroy()
    439.         {
    440.             ResetPreview();
    441.         }
    442.  
    443.         /// <summary>
    444.         /// Compares the names of two objects ignoring case and returns a signed int (-1 for less than, 0  equals, 1 for greater than).
    445.         /// </summary>
    446.         /// <param name="a">The first object to compare</param>
    447.         /// <param name="b">The second object to compare</param>
    448.         /// <returns></returns>
    449.         int NameCompare(Object a, Object b)
    450.         {
    451.             return new CaseInsensitiveComparer().Compare(a.name, b.name);
    452.         }
    453.  
    454.         /// <summary>
    455.         /// Register component-specific copy objects for any components that require special handling.
    456.         /// </summary>
    457.         static void RegisterComponentCopiers()
    458.         {
    459.             componentCopiers.Add(typeof(Transform), new TransformComponentCopier());
    460.             componentCopiers.Add(typeof(MeshRenderer), new MeshRendererComponentCopier());
    461.             componentCopiers.Add(typeof(SkinnedMeshRenderer), new SkinnedMeshRendererComponentCopier());
    462.         }
    463.  
    464.         /// <summary>
    465.         /// Register component-specific property names to avoid copying in a default manner.
    466.         /// </summary>
    467.         static void RegisterComponentPartAvoiders()
    468.         {
    469.             ISet<string> transformAvoiders = new HashSet<string>
    470.             {
    471.                 "localRotation",
    472.                 "localScale",
    473.                 "name",
    474.                 "parent"
    475.             };
    476.             componentPartAvoiders.Add(typeof(Transform), transformAvoiders);
    477.         }
    478.  
    479.         // The interface for component-specific copiers from old to new GameObjects.
    480.         public interface IComponentCopier
    481.         {
    482.             void CopyComponent(ReplacementPreferences replacementPreferences, Component original, GameObject newObject);
    483.         }
    484.  
    485.         // For anything that does not have a component-specific copier, or anything that does but wants to include default copy behaviour.
    486.         public class DefaultComponentCopier : IComponentCopier
    487.         {
    488.             public void CopyComponent(ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    489.             {
    490.                 System.Type type = original.GetType();
    491.                 ISet<string> partAvoiders = componentPartAvoiders.ContainsKey(type) ? componentPartAvoiders[type] : null;
    492.                 var dst = newObject.GetComponent(type);
    493.                 if (!dst) dst = newObject.AddComponent(type);
    494.                 var fields = type.GetFields();
    495.                 foreach (var field in fields)
    496.                 {
    497.                     if (field.IsStatic) continue;
    498.                     if (partAvoiders != null && partAvoiders.Contains(field.Name)) continue;
    499.                     field.SetValue(dst, field.GetValue(original));
    500.                 }
    501.                 var props = type.GetProperties();
    502.                 foreach (var prop in props)
    503.                 {
    504.                     if (!prop.CanWrite || prop.Name == "name" || prop.Name == "parent") continue;
    505.                     if (partAvoiders != null && partAvoiders.Contains(prop.Name)) continue;
    506.                     prop.SetValue(dst, prop.GetValue(original));
    507.                 }
    508.                 // NOTE: Some properties are references to other things and a prefab replacement can break them.
    509.                 // TODO: Should we record any reference types in order to map them to new references later?
    510.             }
    511.         }
    512.  
    513.         // Shared instance of default copier.
    514.         public static DefaultComponentCopier defaultComponentCopier = new DefaultComponentCopier();
    515.  
    516.         /// <summary>
    517.         /// Transform-specific component copier.
    518.         /// </summary>
    519.         public class TransformComponentCopier : IComponentCopier
    520.         {
    521.             public void CopyComponent(ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    522.             {
    523.                 Transform oldTransform = (Transform)original;
    524.                 if (replacementPreferences.applyRotation)
    525.                     newObject.transform.localRotation = oldTransform.localRotation;
    526.  
    527.                 if (replacementPreferences.applyScale)
    528.                     newObject.transform.localScale = oldTransform.localScale;
    529.  
    530.                 if (replacementPreferences.keepOriginalNames)
    531.                     newObject.transform.name = oldTransform.name;
    532.  
    533.                 if (replacementPreferences.keepPlaceInHierarchy)
    534.                     newObject.transform.SetSiblingIndex(oldTransform.GetSiblingIndex());
    535.                 defaultComponentCopier.CopyComponent(replacementPreferences, original, newObject);
    536.             }
    537.         }
    538.  
    539.         /// <summary>
    540.         /// Special for-purpose component copier for mesh renderer.
    541.         /// </summary>
    542.         public class MeshRendererComponentCopier : IComponentCopier
    543.         {
    544.             public void CopyComponent(ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    545.             {
    546.                 MeshRenderer meshRenderer = (MeshRenderer)original;
    547.                 MeshRenderer newMeshRenderer = newObject.GetComponent<MeshRenderer>();
    548.                 // QUESTION Should we instantiate one if one is not present?
    549.                 if (newMeshRenderer)
    550.                 {
    551.                     if (meshRenderer.sharedMaterials.Length == newMeshRenderer.sharedMaterials.Length)
    552.                     {
    553.                         Material[] CacheMaterials = new Material[meshRenderer.sharedMaterials.Length];
    554.                         for (int a = 0; a < meshRenderer.sharedMaterials.Length; a++)
    555.                             CacheMaterials[a] = meshRenderer.sharedMaterials[a];
    556.                         for (int b = 0; b < CacheMaterials.Length; b++)
    557.                             newMeshRenderer.sharedMaterials[b] = CacheMaterials[b];
    558.                     }
    559.                 }
    560.             }
    561.         }
    562.  
    563.         /// <summary>
    564.         /// Special for-purpose component copier for skinned mesh renderer.
    565.         /// </summary>
    566.         public class SkinnedMeshRendererComponentCopier : IComponentCopier
    567.         {
    568.             public void CopyComponent(ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    569.             {
    570.                 SkinnedMeshRenderer meshRenderer = (SkinnedMeshRenderer)original;
    571.                 SkinnedMeshRenderer newMeshRenderer = newObject.GetComponent<SkinnedMeshRenderer>();
    572.                 // QUESTION Should we instantiate one if one is not present?
    573.                 if (newMeshRenderer)
    574.                 {
    575.                     if (meshRenderer.sharedMaterials.Length == newMeshRenderer.sharedMaterials.Length)
    576.                     {
    577.                         Material[] CacheMaterials = new Material[meshRenderer.sharedMaterials.Length];
    578.                         for (int a = 0; a < meshRenderer.sharedMaterials.Length; a++)
    579.                             CacheMaterials[a] = meshRenderer.sharedMaterials[a];
    580.                         for (int b = 0; b < CacheMaterials.Length; b++)
    581.                             newMeshRenderer.sharedMaterials[b] = CacheMaterials[b];
    582.                     }
    583.                 }
    584.             }
    585.         }
    586.     }
    587. }
     
    EAST-DATA and Zan_Kievit like this.
  41. AndronMedia

    AndronMedia

    Joined:
    May 13, 2019
    Posts:
    3
    Hi all, thanks so much for this lifesaver and all of your hard work! What a great tool.
    I was wondering if someone might help me as to why its not working for me in 2020.1.7f1?
    I am getting the attached error: upload_2020-11-4_15-17-11.png
     
    Last edited: Nov 4, 2020
  42. Zan_Kievit

    Zan_Kievit

    Joined:
    Mar 24, 2018
    Posts:
    14
    You seem to be running into a known rename error. Pressing the "Keep names" button should fix that.
     
  43. Zan_Kievit

    Zan_Kievit

    Joined:
    Mar 24, 2018
    Posts:
    14
    After seeing yesterday that the renaming still wasn't fixed, I thought I'dd take a stab at it. And then I let myself go and added more stuff.

    - I've fixed the known errors of renaming.
    - Added all default Numbering Schemes in Unity to the renaming. Which links directly to the project settings.
    - Made it so you can preview the renaming before you apply
    - Improved overall UX, everything is put into a better context, and there is more direct feedback to your actions.

    It's possible that there could be some backward compatibility issues below version 2018, as I don't know when they added Numbering Scheme settings.
    EDIT: This is indeed the case, as it was added in 2020.1. I have edited the script to work with older versions. With the feature regression of only being able to change the numbering scheme in the code on line 586 if used in older versions.

    Code (CSharp):
    1.  
    2. /*=================== Replace with Prefab ===================
    3. Unity Forum Community Thread https://forum.unity.com/threads/replace-game-object-with-prefab.24311/
    4. Tested in 2018.4.19f1, 2019.3.6f1, 2020.1.12f1
    5. Should work in pre-2018.3 versions with old prefab workflow (Needs testing)
    6. Changelog and contributors:
    7. v1.0.0 (2010-03) Original CopyComponents by Michael L. Croswell for Colorado Game Coders, LLC
    8. v1.1.0 (2011-06) by Kristian Helle Jespersen
    9. v1.2.0 (2015-04) by Connor Cadellin McKee for Excamedia
    10. v1.3.0 (2015-04) by Fernando Medina (fermmmm)
    11. v1.4.0 (2015-07) by Julien Tonsuso (www.julientonsuso.com)
    12. v1.5.0 (2017-06) by Alex Dovgodko
    13.                  Changed into editor window and added instant preview in scene view
    14. v1.6.0 (2018-03) by ???
    15.                  Made changes to make things work with Unity 5.6.1
    16. v1.7.0 (2018-05) by Carlos Diosdado (hypertectonic)
    17.                  Added link to community thread, booleans to choose if scale and rotation are applied, mark scene as dirty, changed menu item
    18. v1.8.0 (2018-??) by Virgil Iordan
    19.                  Added KeepPlaceInHierarchy
    20. v1.9.0 (2019-01) by Dev Bye-A-Jee, Sanjay Sen & Nick Rodriguez for Ravensbourne University London
    21.                  Added unique numbering identifier in the hierarchy to each newly instantiated prefab, also accounts for existing numbers
    22. v2.0.0 (2020-03-22) by Zan Kievit
    23.                     Made compatible with the new Prefab system of Unity 2018. Made more user friendly and added undo.
    24. v2.1.0 (2020-03-22) by Carlos Diosdado (hypertectonic)
    25.                     Added options to use as a utility window (show from right click in the hierarchy), min/max window size,
    26.                     backwards compatibility for old prefab system, works with prefabs selected in project browser, fixed not replacing prefabs,
    27.                     added version numbers, basic documentation, Community namespace to avoid conflicts, cleaned up code for readability.
    28. v2.2.0 (2020-03-22) by GGHitman
    29.                     Add Search by tag or by layer
    30.                     the object will replace the tag and the layer of the original object
    31.                     compare and exchange materials
    32. v.2.3.0 (2020-10-20) by Jade Annand
    33.                      Added recursive game object, component, field and value copying.
    34. v.2.4.0 (2020-11-9) by Zan Kievit
    35.                     Fixed Rename errors. Added Numbering Schemes from project settings to Rename, dynamic preview of Rename, improved overal UX.
    36.                     Added NaturalComparer class from https://www.codeproject.com/Articles/22517/Natural-Sort-Comparer for human readable sorting.
    37.  
    38. Known Errors: None
    39. ============================================================*/
    40.  
    41. using UnityEngine;
    42. using UnityEditor;
    43. using UnityEditor.SceneManagement;
    44. using System;
    45. using System.Collections.Generic;
    46. using System.Text.RegularExpressions;
    47. using System.Linq;
    48.  
    49. namespace Community
    50. {
    51.     /// <summary>
    52.     /// An editor tool to replace selected GameObjects with a specified Prefab.
    53.     /// </summary>
    54.     public class ReplaceWithPrefab : EditorWindow
    55.     {
    56.         public GameObject prefab = null;
    57.         public GameObject oldPrefab = null;
    58.         public List<GameObject> objectsToReplace = new List<GameObject>();
    59.         public List<GameObject> newObjects = new List<GameObject>();
    60.         public List<string> objectPreview = new List<string>();
    61.         public bool editMode = false;
    62.  
    63.         public struct ReplacementPreferences
    64.         {
    65.             public bool renameObjects;
    66.             public bool orderHierarchyToPreview;
    67.             public bool applyRotation;
    68.             public bool applyScale;
    69.         }
    70.  
    71.         public ReplacementPreferences replacementPreferences;
    72.  
    73.         NamingScheme namingScheme;
    74.         public enum NamingScheme
    75.         {
    76.             SpaceParenthesis,
    77.             Dot,
    78.             Underscore
    79.         }
    80.  
    81.         public bool SearchWithTag = false;
    82.         public string TagForSearch = "Untagged";
    83.         public GameObject[] searchResult;
    84.  
    85.         public bool SearchWithLayer = false;
    86.         public int LayerForSearch;
    87.  
    88.  
    89.         private Vector2 windowMinSize = new Vector2(450, 300);
    90.         private Vector2 windowMaxSize = new Vector2(800, 1000);
    91.         private Vector2 scrollPosition;
    92.  
    93.         private static readonly IDictionary<System.Type, IComponentCopier> componentCopiers = new Dictionary<System.Type, IComponentCopier>();
    94.         private static readonly IDictionary<System.Type, ISet<string>> componentPartAvoiders = new Dictionary<System.Type, ISet<string>>();
    95.  
    96.         static ReplaceWithPrefab ()
    97.         {
    98.             RegisterComponentCopiers();
    99.             RegisterComponentPartAvoiders();
    100.         }
    101.  
    102.         /// <summary>
    103.         /// Gets or creates a new Replace with Prefab window.
    104.         /// </summary>
    105.         [MenuItem("Tools/Community/Replace with Prefab")]
    106.         static void StartWindow ()
    107.         {
    108.             ReplaceWithPrefab window = (ReplaceWithPrefab)GetWindow(typeof(ReplaceWithPrefab));
    109.             window.Show();
    110.  
    111.             window.titleContent = new GUIContent("Replace with Prefab");
    112.             window.minSize = window.windowMinSize;
    113.             window.maxSize = window.windowMaxSize;
    114.         }
    115.  
    116.         public ReplaceWithPrefab ()
    117.         {
    118.             replacementPreferences.renameObjects = false;
    119.             replacementPreferences.orderHierarchyToPreview = false;
    120.             replacementPreferences.applyRotation = true;
    121.             replacementPreferences.applyScale = true;
    122.         }
    123.  
    124.         /// <summary>
    125.         /// Handles getting the selected objects when the selection changes.
    126.         /// </summary>
    127.         void OnSelectionChange ()
    128.         {
    129.             GetSelection();
    130.             Repaint();
    131.         }
    132.  
    133.         /// <summary>
    134.         /// Draws the window content: object list, configuration and execution buttons.
    135.         /// </summary>
    136.         void OnGUI ()
    137.         {
    138.             #region Draw Top Buttons
    139.  
    140.             GUILayout.BeginHorizontal(EditorStyles.toolbar);
    141.             {
    142.                 editMode = GUILayout.Toggle(editMode, new GUIContent("Start replacing", "Start using this feature"), EditorStyles.toggle);
    143.                 GUILayout.FlexibleSpace();
    144.             }
    145.             GUILayout.EndHorizontal();
    146.             #endregion
    147.  
    148.             #region "TAG LAYER"
    149.  
    150.             SearchWithTag = GUILayout.Toggle(!SearchWithLayer ? SearchWithTag : false, "Apply Search By Tag", EditorStyles.toggle);
    151.             SearchWithLayer = GUILayout.Toggle(!SearchWithTag ? SearchWithLayer : false, "Apply Search By Layer");
    152.  
    153.             if (SearchWithTag)
    154.             {
    155.                 GUILayout.Space(5);
    156.                 TagForSearch = EditorGUILayout.TagField("Set tag :  ", TagForSearch);
    157.             }
    158.             else if (SearchWithLayer)
    159.             {
    160.                 GUILayout.Space(5);
    161.                 LayerForSearch = EditorGUILayout.LayerField("Set layer :  ", LayerForSearch);
    162.             }
    163.             #endregion "TAG LAYER"
    164.  
    165.             if (GUI.changed)
    166.             {
    167.                 if (editMode)
    168.                     GetSelection();
    169.                 else
    170.                     ResetPreview();
    171.             }
    172.  
    173.             GUILayout.Space(10);
    174.             if (editMode)
    175.             {
    176.                 SetNamingScheme();
    177.                 RenamePreview();
    178.  
    179.                 #region Draw Prefab and List
    180.  
    181.                 GUILayout.Label("Prefab: ", EditorStyles.boldLabel);
    182.                 prefab = (GameObject)EditorGUILayout.ObjectField(prefab, typeof(GameObject), true);
    183.                 if(oldPrefab != prefab)
    184.                 {
    185.                     GetSelection();
    186.                     oldPrefab = prefab;
    187.                 }
    188.                 GUILayout.Space(10);
    189.  
    190.                 if (prefab != null)
    191.                 {
    192.                     if (objectsToReplace.Count > 0)
    193.                     {
    194.                         GUILayout.Label(new GUIContent("Objects to be Replaced:", (!SearchWithTag && !SearchWithLayer) ? "Multi-select all the objects you want to replace with your Prefab" : ""), EditorStyles.boldLabel);
    195.  
    196.                         objectPreview.Sort(new NaturalComparer());
    197.  
    198.                         scrollPosition = GUILayout.BeginScrollView(scrollPosition, EditorStyles.helpBox);
    199.                         {
    200.                             GUILayout.BeginHorizontal(EditorStyles.helpBox);
    201.                             {
    202.                                 string previewText = "No Preview";
    203.  
    204.                                 if (replacementPreferences.renameObjects && !replacementPreferences.orderHierarchyToPreview)
    205.                                     previewText = "Preview of Renaming";
    206.                                 else if (replacementPreferences.orderHierarchyToPreview && !replacementPreferences.renameObjects)
    207.                                     previewText = "Preview of Hierarchy Order";
    208.                                 else if (replacementPreferences.orderHierarchyToPreview && replacementPreferences.renameObjects)
    209.                                     previewText = "Preview of Renaming and Hierarchy Order";
    210.  
    211.                                 GUILayout.Label(previewText, EditorStyles.miniLabel);
    212.                             }
    213.                             GUILayout.EndHorizontal();
    214.  
    215.                             foreach (string go in objectPreview)
    216.                             {
    217.                                 GUILayout.BeginHorizontal(EditorStyles.toolbar);
    218.                                 GUILayout.Label(go);
    219.                                 GUILayout.EndHorizontal();
    220.                             }
    221.                             GUILayout.Space(2);
    222.                         }
    223.                         GUILayout.EndScrollView();
    224.  
    225.                         GUILayout.Space(5);
    226.  
    227.                         replacementPreferences.renameObjects = GUILayout.Toggle(replacementPreferences.renameObjects, "Rename replaced objects", EditorStyles.toggle);
    228.                         replacementPreferences.orderHierarchyToPreview = GUILayout.Toggle(replacementPreferences.orderHierarchyToPreview, "Oder hierarchy to preview", EditorStyles.toggle);
    229.                         GUILayout.Space(10);
    230.                         replacementPreferences.applyRotation = GUILayout.Toggle(replacementPreferences.applyRotation, "Apply rotation", EditorStyles.toggle);
    231.                         replacementPreferences.applyScale = GUILayout.Toggle(replacementPreferences.applyScale, "Apply scale", EditorStyles.toggle);
    232.  
    233.                     }
    234.                     else if(!SearchWithTag && !SearchWithLayer)
    235.                     {
    236.                         GUILayout.Label(new GUIContent("Multi-select all the objects you want to replace with your Prefab"), EditorStyles.boldLabel);
    237.                     }
    238.                 }
    239.                 else
    240.                 {
    241.                     GUILayout.Label("Select a Prefab to replace objects with", EditorStyles.boldLabel);
    242.                 }
    243.                 #endregion
    244.  
    245.                 #region Draw Bottom Buttons
    246.  
    247.                 GUILayout.Space(5);
    248.                 GUILayout.BeginHorizontal();
    249.                 {
    250.                     if (prefab != null && objectsToReplace.Count > 0)
    251.                     {
    252.                         if (GUILayout.Button("Apply"))
    253.                         {
    254.                             foreach (GameObject go in objectsToReplace)
    255.                             {
    256.                                 Replace(go);
    257.                                 DestroyImmediate(go);
    258.                             }
    259.                             if (replacementPreferences.renameObjects)
    260.                             {
    261.                                 Rename();
    262.                             }
    263.                             editMode = false;
    264.                             EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); // Important so that we don't forget to save!
    265.                         }
    266.                         else if (GUILayout.Button("Cancel"))
    267.                         {
    268.                             objectsToReplace.Clear();
    269.                             objectPreview.Clear();
    270.                             ResetPreview();
    271.                             prefab = null;
    272.                         }
    273.                     }
    274.                 }
    275.                 GUILayout.EndHorizontal();
    276.                 #endregion
    277.             }
    278.             else
    279.             {
    280.                 objectsToReplace.Clear();
    281.                 objectPreview.Clear();
    282.                 newObjects.Clear();
    283.                 prefab = null;
    284.             }
    285.         }
    286.  
    287.         /// <summary>
    288.         /// Renames the gameObjects, adding numbering following the Naming Scheme Set in the Project Settings.
    289.         /// It checks for already used numbers.
    290.         /// </summary>
    291.         void Rename ()
    292.         {
    293.             int count = 0;
    294.             List<int> ExistingNumbers = new List<int>();
    295.  
    296.             SetExistingNumbers(newObjects, ExistingNumbers, namingScheme);
    297.  
    298.             //Apply new names
    299.             foreach (GameObject go in newObjects)
    300.             {
    301.                 count = GetCount(count, ExistingNumbers);
    302.                 switch (namingScheme)
    303.                 {
    304.                     case NamingScheme.SpaceParenthesis:
    305.                         go.name = prefab.name + " (" + count + ")";
    306.                         break;
    307.                     case NamingScheme.Dot:
    308.                         go.name = prefab.name + "." + count;
    309.                         break;
    310.                     case NamingScheme.Underscore:
    311.                         go.name = prefab.name + "_" + count;
    312.                         break;
    313.                 }
    314.             }
    315.         }
    316.  
    317.         /// <summary>
    318.         /// Renames the list of names, adding numbering following the Naming Scheme Set in the Project Settings.
    319.         /// It checks for already used numbers.
    320.         /// </summary>
    321.         void RenamePreview ()
    322.         {
    323.             int count = 0;
    324.             List<int> ExistingNumbers = new List<int>();
    325.             objectPreview.Clear();
    326.  
    327.             if (replacementPreferences.renameObjects)
    328.             {
    329.                 SetExistingNumbers(objectsToReplace, ExistingNumbers, namingScheme);
    330.             }
    331.             //Apply new names
    332.             for (int n = 0; n < objectsToReplace.Count; n++)
    333.             {
    334.                 if (replacementPreferences.renameObjects)
    335.                 {
    336.                     count = GetCount(count, ExistingNumbers);
    337.                     switch (namingScheme)
    338.                     {
    339.                         case NamingScheme.SpaceParenthesis:
    340.                             objectPreview.Add(prefab.name + " (" + count + ")");
    341.                             break;
    342.                         case NamingScheme.Dot:
    343.                             objectPreview.Add(prefab.name + "." + count);
    344.                             break;
    345.                         case NamingScheme.Underscore:
    346.                             objectPreview.Add(prefab.name + "_" + count);
    347.                             break;
    348.                     }
    349.                 }
    350.                 else if(!replacementPreferences.renameObjects)
    351.                     objectPreview.Add(objectsToReplace[n].name);
    352.             }
    353.         }
    354.  
    355.         /// <summary>
    356.         /// Set existing numbers based on the naming scheme set in the project settings
    357.         /// </summary>
    358.         /// <param name="objects">The list of objects to get the names from</param>
    359.         /// <param name="ExistingNumbers">The list of ExistingNumbers to set</param>
    360.         /// <param name="namingScheme">The naming scheme to use</param>
    361.         void SetExistingNumbers (List<GameObject> objects, List<int> ExistingNumbers, NamingScheme namingScheme)
    362.         {
    363.             foreach (GameObject obj in objects)
    364.             {
    365.                 string name = obj.name;
    366.                 if (name.Contains(prefab.name) && name.Any(char.IsDigit))
    367.                 {
    368.                     int num = 0;
    369.                     switch (namingScheme)
    370.                     {
    371.                         case NamingScheme.SpaceParenthesis:
    372.                             char[] charsToTrim = { '(', ')' };
    373.                             num = GetExistingNumber(name, name.Split(' '), charsToTrim);
    374.                             break;
    375.                         case NamingScheme.Dot:
    376.                             num = GetExistingNumber(name, name.Split('.'));
    377.                             break;
    378.                         case NamingScheme.Underscore:
    379.                             num = GetExistingNumber(name, name.Split('_'));
    380.                             break;
    381.                     }
    382.                     if(num != 0)
    383.                         ExistingNumbers.Add(num);
    384.                     else
    385.                         Debug.LogError("The selected object cannot be renamed, as there are several naming schemes used");
    386.                 }
    387.             }
    388.         }
    389.  
    390.         /// <summary>
    391.         /// Finds the "space" character in the name to identify where the number is, then if needed, strips provided extra characters.
    392.         /// </summary>
    393.         /// <param name="name">The name of the object</param>
    394.         /// <param name="splitChars">The string array</param>
    395.         /// <param name="charsToTrim">The extra characters to trim before converting the string to an int</param>
    396.         int GetExistingNumber (string name, string[] splitChars, char[] charsToTrim = null)
    397.         {
    398.             int count = 1;
    399.  
    400.             if (splitChars.Length > 1)
    401.             {
    402.                 string digit = splitChars[1]; // substring which contains number
    403.  
    404.                 //Get the substring that contains digits
    405.                 while (GetDigits(digit) == "")
    406.                 {
    407.                     count++;
    408.                     digit = GetDigits(splitChars[count]);
    409.                 }
    410.                
    411.                 if (charsToTrim != null)
    412.                     digit = digit.Trim(charsToTrim);
    413.  
    414.                 return int.Parse(GetDigits(digit)); // convert string to number
    415.             }
    416.             else
    417.             {
    418.                 return int.Parse(GetDigits(name));
    419.             }
    420.         }
    421.  
    422.         /// <summary>
    423.         /// The number to give the
    424.         /// </summary>
    425.         /// <param name="count">The name of the object</param>
    426.         /// <param name="ExistingNumbers">The existing numbers to keep</param>
    427.         int GetCount (int count, List<int> ExistingNumbers)
    428.         {
    429.             if (ExistingNumbers.Count > 0)
    430.             {
    431.                 int i = 0;
    432.                 while (i < ExistingNumbers.Count)
    433.                 {
    434.                     if (count == ExistingNumbers[i])
    435.                     {
    436.                         count++;
    437.                         i = 0;
    438.                         return count;
    439.                     }
    440.                     else
    441.                         i++;
    442.                 }
    443.             }
    444.             count++;
    445.             return count;
    446.         }
    447.  
    448.         /// <summary>
    449.         /// Replaces a given gameObject with a previously chosen prefab.
    450.         /// </summary>
    451.         /// <param name="obj">The gameObject to replace.</param>
    452.         void Replace (GameObject obj)
    453.         {
    454.             GameObject newObject;
    455.  
    456.             newObject = PrefabUtility.InstantiatePrefab(PrefabUtility.GetCorrespondingObjectFromSource(prefab)) as GameObject;
    457.  
    458.             if (newObject == null) // if the prefab is chosen from the project browser and not the hierarchy, it is null
    459.                 newObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
    460.  
    461.             newObject.transform.SetParent(obj.transform.parent, true);
    462.  
    463.             newObjects.Add(newObject);
    464.  
    465.             CopyContentsToNew(obj, newObject);
    466.  
    467.             Undo.RegisterCreatedObjectUndo(newObject, "Replaced Objects");
    468.             Undo.DestroyObjectImmediate(obj);
    469.         }
    470.  
    471.         private void CopyContentsToNew (GameObject oldObject, GameObject newObject)
    472.         {
    473.             newObject.tag = oldObject.tag;
    474.             newObject.layer = oldObject.layer;
    475.  
    476.             Component[] components = oldObject.GetComponents(typeof(Component));
    477.             foreach (Component component in components)
    478.             {
    479.                 IComponentCopier copier = null;
    480.                 System.Type componentType = component.GetType();
    481.                 while (copier == null)
    482.                 {
    483.                     if (componentCopiers.ContainsKey(componentType))
    484.                         copier = componentCopiers[componentType];
    485.                     else if (componentType.BaseType == typeof(System.Object) ||
    486.                         componentType.BaseType == null)
    487.                         copier = defaultComponentCopier;
    488.                     else
    489.                         componentType = componentType.BaseType; // Components may be derivatives, so look up the tree.
    490.                 }
    491.                 copier.CopyComponent(replacementPreferences, component, newObject);
    492.             }
    493.             int childCount = oldObject.transform.childCount;
    494.             for (int i = 0; i < oldObject.transform.childCount; i++)
    495.             {
    496.                 GameObject child = oldObject.transform.GetChild(i).gameObject;
    497.                 GameObject newChild;
    498.                 Transform newChildTransform = newObject.transform.Find(child.name);
    499.                 if (newChildTransform == null)
    500.                 {
    501.                     newChild = new GameObject(child.name);
    502.                     newChild.transform.SetParent(newObject.transform, false);
    503.                 }
    504.                 else
    505.                     newChild = newChildTransform.gameObject;
    506.                 CopyContentsToNew(child, newChild);
    507.             }
    508.         }
    509.  
    510.         /// <summary>
    511.         /// Gets the currently selected game objects.
    512.         /// </summary>
    513.         void GetSelection ()
    514.         {
    515.             SetNamingScheme();
    516.  
    517.             if (editMode && Selection.activeGameObject != null && (prefab == null || (!SearchWithTag && !SearchWithLayer)))
    518.             {
    519.                 if (prefab == null) // get the prefab 1st
    520.                 {
    521.                     PrefabAssetType t = PrefabUtility.GetPrefabAssetType(Selection.activeGameObject);
    522.  
    523.                     if (t == PrefabAssetType.Regular || t == PrefabAssetType.Variant)
    524.                     {
    525.                         prefab = Selection.activeGameObject;
    526.                         oldPrefab = Selection.activeGameObject;
    527.                     }
    528.                 }
    529.                 else // get the other objects
    530.                 {
    531.                     ResetPreview();
    532.                     objectPreview.Clear();
    533.                     objectsToReplace.Clear();
    534.                     foreach (var obj in Selection.gameObjects)
    535.                     {
    536.                         if(obj != prefab)
    537.                             objectsToReplace.Add(obj);
    538.                     }
    539.                 }
    540.             }
    541.             if(editMode && prefab != null && (SearchWithTag || SearchWithLayer))
    542.             {
    543.                 if (SearchWithTag)
    544.                 {
    545.                     ResetPreview();
    546.                     objectPreview.Clear();
    547.                     objectsToReplace.Clear();
    548.                     GameObject[] allGameObjects = GameObject.FindObjectsOfType<GameObject>();
    549.                     foreach (var gg in allGameObjects)
    550.                     {
    551.                         if (gg.tag == TagForSearch)
    552.                         {
    553.                             if (gg != prefab)
    554.                                 objectsToReplace.Add(gg);
    555.                         }
    556.                     }
    557.                 }
    558.                 else if (SearchWithLayer)
    559.                 {
    560.                     ResetPreview();
    561.                     objectPreview.Clear();
    562.                     objectsToReplace.Clear();
    563.                     GameObject[] allGameObjects = GameObject.FindObjectsOfType<GameObject>();
    564.                     foreach (var gg in allGameObjects)
    565.                     {
    566.                         if (gg.layer == LayerForSearch)
    567.                         {
    568.                             if (gg != prefab)
    569.                                 objectsToReplace.Add(gg);
    570.                         }
    571.                     }
    572.                 }
    573.             }
    574.             else if(editMode && Selection.activeGameObject == null && prefab != null && !SearchWithTag && !SearchWithLayer)
    575.             {
    576.                 ResetPreview();
    577.                 objectPreview.Clear();
    578.                 objectsToReplace.Clear();
    579.             }
    580.         }
    581.  
    582.         void SetNamingScheme()
    583.         {
    584. #if UNITY_2020_OR_NEWER
    585.             namingScheme = EditorSettings.gameObjectNamingScheme;
    586. #else
    587.             namingScheme = NamingScheme.SpaceParenthesis;
    588. #endif
    589.         }
    590.  
    591.         /// <summary>
    592.         /// Resets the gameObject preview.
    593.         /// </summary>
    594.         void ResetPreview ()
    595.         {
    596.             if (newObjects != null)
    597.             {
    598.                 foreach (GameObject go in newObjects)
    599.                 {
    600.                     DestroyImmediate(go);
    601.                 }
    602.             }
    603.             newObjects.Clear();
    604.         }
    605.  
    606.         /// <summary>
    607.         /// Handles window destruction.
    608.         /// </summary>
    609.         void OnDestroy ()
    610.         {
    611.             ResetPreview();
    612.         }
    613.  
    614.         /// <summary>
    615.         /// Takes all digits from a string and returns them as one string.
    616.         /// </summary>
    617.         /// <param name="text">The string to get the digits from</param>
    618.         /// <returns>A string of digits</returns>
    619.         string GetDigits (string text)
    620.         {
    621.             string digits = "";
    622.             for (int i = 0; i < text.Length; i++)
    623.             {
    624.                 if (char.IsDigit(text[i]))
    625.                 {
    626.                     digits += text[i];
    627.                 }
    628.             }
    629.             return digits;
    630.         }
    631.  
    632.         /// <summary>
    633.         /// ASCII comparer class
    634.         /// </summary>
    635.         public class NaturalComparer : Comparer<string>, IDisposable
    636.         {
    637.             private Dictionary<string, string[]> table;
    638.  
    639.             public NaturalComparer ()
    640.             {
    641.                 table = new Dictionary<string, string[]>();
    642.             }
    643.  
    644.             public void Dispose ()
    645.             {
    646.                 table.Clear();
    647.                 table = null;
    648.             }
    649.  
    650.             public override int Compare (string x, string y)
    651.             {
    652.                 if (x == y)
    653.                 {
    654.                     return 0;
    655.                 }
    656.                 string[] x1, y1;
    657.                 if (!table.TryGetValue(x, out x1))
    658.                 {
    659.                     x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
    660.                     table.Add(x, x1);
    661.                 }
    662.                 if (!table.TryGetValue(y, out y1))
    663.                 {
    664.                     y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
    665.                     table.Add(y, y1);
    666.                 }
    667.  
    668.                 for (int i = 0; i < x1.Length && i < y1.Length; i++)
    669.                 {
    670.                     if (x1[i] != y1[i])
    671.                     {
    672.                         return PartCompare(x1[i], y1[i]);
    673.                     }
    674.                 }
    675.                 if (y1.Length > x1.Length)
    676.                 {
    677.                     return 1;
    678.                 }
    679.                 else if (x1.Length > y1.Length)
    680.                 {
    681.                     return -1;
    682.                 }
    683.                 else
    684.                 {
    685.                     return 0;
    686.                 }
    687.             }
    688.  
    689.             private static int PartCompare (string left, string right)
    690.             {
    691.                 int x, y;
    692.                 if (!int.TryParse(left, out x))
    693.                 {
    694.                     return left.CompareTo(right);
    695.                 }
    696.  
    697.                 if (!int.TryParse(right, out y))
    698.                 {
    699.                     return left.CompareTo(right);
    700.                 }
    701.  
    702.                 return x.CompareTo(y);
    703.             }
    704.         }
    705.  
    706.         /// <summary>
    707.         /// Register component-specific copy objects for any components that require special handling.
    708.         /// </summary>
    709.         static void RegisterComponentCopiers ()
    710.         {
    711.             componentCopiers.Add(typeof(Transform), new TransformComponentCopier());
    712.             componentCopiers.Add(typeof(MeshRenderer), new MeshRendererComponentCopier());
    713.             componentCopiers.Add(typeof(SkinnedMeshRenderer), new SkinnedMeshRendererComponentCopier());
    714.         }
    715.  
    716.         /// <summary>
    717.         /// Register component-specific property names to avoid copying in a default manner.
    718.         /// </summary>
    719.         static void RegisterComponentPartAvoiders ()
    720.         {
    721.             ISet<string> transformAvoiders = new HashSet<string>
    722.             {
    723.                 "localRotation",
    724.                 "localScale",
    725.                 "name",
    726.                 "parent"
    727.             };
    728.             componentPartAvoiders.Add(typeof(Transform), transformAvoiders);
    729.         }
    730.  
    731.         // The interface for component-specific copiers from old to new GameObjects.
    732.         public interface IComponentCopier
    733.         {
    734.             void CopyComponent (ReplacementPreferences replacementPreferences, Component original, GameObject newObject);
    735.         }
    736.  
    737.         // For anything that does not have a component-specific copier, or anything that does but wants to include default copy behaviour.
    738.         public class DefaultComponentCopier : IComponentCopier
    739.         {
    740.             public void CopyComponent (ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    741.             {
    742.                 System.Type type = original.GetType();
    743.                 ISet<string> partAvoiders = componentPartAvoiders.ContainsKey(type) ? componentPartAvoiders[type] : null;
    744.                 var dst = newObject.GetComponent(type);
    745.                 if (!dst)
    746.                     dst = newObject.AddComponent(type);
    747.                 var fields = type.GetFields();
    748.                 foreach (var field in fields)
    749.                 {
    750.                     if (field.IsStatic)
    751.                         continue;
    752.                     if (partAvoiders != null && partAvoiders.Contains(field.Name))
    753.                         continue;
    754.                     field.SetValue(dst, field.GetValue(original));
    755.                 }
    756.                 var props = type.GetProperties();
    757.                 foreach (var prop in props)
    758.                 {
    759.                     if (!prop.CanWrite || prop.Name == "name" || prop.Name == "parent")
    760.                         continue;
    761.                     if (partAvoiders != null && partAvoiders.Contains(prop.Name))
    762.                         continue;
    763.                     prop.SetValue(dst, prop.GetValue(original));
    764.                 }
    765.                 // NOTE: Some properties are references to other things and a prefab replacement can break them.
    766.                 // TODO: Should we record any reference types in order to map them to new references later?
    767.             }
    768.         }
    769.  
    770.         // Shared instance of default copier.
    771.         public static DefaultComponentCopier defaultComponentCopier = new DefaultComponentCopier();
    772.  
    773.         /// <summary>
    774.         /// Transform-specific component copier.
    775.         /// </summary>
    776.         public class TransformComponentCopier : IComponentCopier
    777.         {
    778.             public void CopyComponent (ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    779.             {
    780.                 Transform oldTransform = (Transform)original;
    781.                 if (replacementPreferences.applyRotation)
    782.                     newObject.transform.localRotation = oldTransform.localRotation;
    783.  
    784.                 if (replacementPreferences.applyScale)
    785.                     newObject.transform.localScale = oldTransform.localScale;
    786.  
    787.                 if (!replacementPreferences.renameObjects)
    788.                     newObject.transform.name = oldTransform.name;
    789.  
    790.                 if (!replacementPreferences.orderHierarchyToPreview)
    791.                     newObject.transform.SetSiblingIndex(oldTransform.GetSiblingIndex());
    792.                 defaultComponentCopier.CopyComponent(replacementPreferences, original, newObject);
    793.             }
    794.         }
    795.  
    796.         /// <summary>
    797.         /// Special for-purpose component copier for mesh renderer.
    798.         /// </summary>
    799.         public class MeshRendererComponentCopier : IComponentCopier
    800.         {
    801.             public void CopyComponent (ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    802.             {
    803.                 MeshRenderer meshRenderer = (MeshRenderer)original;
    804.                 MeshRenderer newMeshRenderer = newObject.GetComponent<MeshRenderer>();
    805.                 // QUESTION Should we instantiate one if one is not present?
    806.                 if (newMeshRenderer)
    807.                 {
    808.                     if (meshRenderer.sharedMaterials.Length == newMeshRenderer.sharedMaterials.Length)
    809.                     {
    810.                         Material[] CacheMaterials = new Material[meshRenderer.sharedMaterials.Length];
    811.                         for (int a = 0; a < meshRenderer.sharedMaterials.Length; a++)
    812.                             CacheMaterials[a] = meshRenderer.sharedMaterials[a];
    813.                         for (int b = 0; b < CacheMaterials.Length; b++)
    814.                             newMeshRenderer.sharedMaterials[b] = CacheMaterials[b];
    815.                     }
    816.                 }
    817.             }
    818.         }
    819.  
    820.         /// <summary>
    821.         /// Special for-purpose component copier for skinned mesh renderer.
    822.         /// </summary>
    823.         public class SkinnedMeshRendererComponentCopier : IComponentCopier
    824.         {
    825.             public void CopyComponent (ReplacementPreferences replacementPreferences, Component original, GameObject newObject)
    826.             {
    827.                 SkinnedMeshRenderer meshRenderer = (SkinnedMeshRenderer)original;
    828.                 SkinnedMeshRenderer newMeshRenderer = newObject.GetComponent<SkinnedMeshRenderer>();
    829.                 // QUESTION Should we instantiate one if one is not present?
    830.                 if (newMeshRenderer)
    831.                 {
    832.                     if (meshRenderer.sharedMaterials.Length == newMeshRenderer.sharedMaterials.Length)
    833.                     {
    834.                         Material[] CacheMaterials = new Material[meshRenderer.sharedMaterials.Length];
    835.                         for (int a = 0; a < meshRenderer.sharedMaterials.Length; a++)
    836.                             CacheMaterials[a] = meshRenderer.sharedMaterials[a];
    837.                         for (int b = 0; b < CacheMaterials.Length; b++)
    838.                             newMeshRenderer.sharedMaterials[b] = CacheMaterials[b];
    839.                     }
    840.                 }
    841.             }
    842.         }
    843.     }
    844. }
    845.  
     
    Last edited: Jan 23, 2021
    ksf000, jwinn, jGate99 and 3 others like this.
  44. atifmahmood29

    atifmahmood29

    Joined:
    Nov 23, 2014
    Posts:
    8
    also check active state
    newObject.SetActive(go.activeSelf);

     
  45. eof2007

    eof2007

    Joined:
    Apr 18, 2020
    Posts:
    8
    Hello Friend
    Thank you for the revised script.

    I do not have a very high level of programming, please tell me why on v.2.4.0 the script gives an error due to EditorSettings.NamingScheme namingScheme;
    Everything after EditorSettings in the whole script with an error
     
  46. Zan_Kievit

    Zan_Kievit

    Joined:
    Mar 24, 2018
    Posts:
    14
    As I suspected, the naming schemes have only been recently added to Unity. I have edited my version of the script in the original post. It should now be working with versions below 2020.1, with the feature regression of only having the basic "SpaceParenthesis" naming scheme by default, which is only changeable in the script as of right now.
     
    MlleBun and eof2007 like this.
  47. gghitman69

    gghitman69

    Joined:
    Mar 4, 2016
    Posts:
    93
    Hi for those who think about improvements post your requests and see what we can do
     
  48. eof2007

    eof2007

    Joined:
    Apr 18, 2020
    Posts:
    8
    Hi
    Unity 2019.4.18f
    The script works, but when trying to build the game, an error appears

    Assets\Bone Palaces\Scripts\ReplaceWithPrefab.cs(42,19): error CS0234: The type or namespace name 'SceneManagement' does not exist in the namespace 'UnityEditor' (are you missing an assembly reference?)
    Assets\Bone Palaces\Scripts\ReplaceWithPrefab.cs(53,38): error CS0246: The type or namespace name 'EditorWindow' could not be found (are you missing a using directive or an assembly reference?)
    Assets\Bone Palaces\Scripts\ReplaceWithPrefab.cs(104,10): error CS0246: The type or namespace name 'MenuItemAttribute' could not be found (are you missing a using directive or an assembly reference?)
    Assets\Bone Palaces\Scripts\ReplaceWithPrefab.cs(104,10): error CS0246: The type or namespace name 'MenuItem' could not be found (are you missing a using directive or an assembly reference?)
     
  49. Zan_Kievit

    Zan_Kievit

    Joined:
    Mar 24, 2018
    Posts:
    14
    The script is an editor script that can't be included in builds. Simply make a folder specifically called Editor, and put the script in there to exclude it from the build.
     
  50. RJTimmerman

    RJTimmerman

    Joined:
    Nov 25, 2020
    Posts:
    1
    I just used the latest version of this script by Zan_Kievit, but it didn't fully work (Unity 2019.4.15f1, not in play mode).
    It replaced all the objects (11) with the desired prefab, but it came with a whole army of errors, and some undesired overrides.
    The overrides are:
    Capsule mesh filter into "Capsule Instance" mesh filter;
    An (I believe non-existent) physics material added to the collider;
    Rigidbody Is Kinematic unchecked and constraints added for freezing position and all but Y rotation;
    Some of the custom script variables changed;
    Cylinder mesh filter into "CylinderInstance" mesh filter (in child of child);
    An (I believe non-existent) physics material added to the collider (in child of child).
    See the screenshot below for the errors, I got all of these 11 times (one time for each object):
    upload_2021-4-11_21-45-39.png

    I fixed the overrides by just selecting all of my (now prefabbed) game objects again and simply reverting overrides. But this is something that you might want to take a look at fixing if you still want to continue work on this script.
    Still an awesome script and amazing to see how it developed in this thread, thank you all!