3
\$\begingroup\$

I have around 100 objects (prefab A) in my scene, all in different positions.

Is it possible to replace all of these objects with another object (prefab B), so that the prefab B objects are placed in the same position as the prefab A objects were?

I want this done in the editor, not in game.

\$\endgroup\$

4 Answers 4

2
\$\begingroup\$

This can be easily done, manually, in a variety of ways. Unfortunately, you report having 100 game objects that you wish to exchange, in this way. Rather than manually completing the task, let us write a script to do it.

Note that this is still specific to the editor. Using the namespace UnityEditor, you have the ability to manipulate the editor, which allows you to complete repetitive tasks such as this one.


This is a stand alone script that you can attach to any game object, in order to complete the described task with less repetition. It allows you to replace game objects en mass, by either storing them into an array, or by using tags to automatically construct an array.

Note that you specifically mention position. I also take rotation in to account, as well as potential parenting. If you do not wish to include rotation, simply use Quaternion.identity for the rotation value. If you do not wish to include parenting, simply remove the if statement that handles it.

using UnityEngine;  // UnityEngine gives us general access.
using UnityEditor;  // UnityEditor gives us editor-specific access.

/// <summary>Performs manual iteration to swap out one game object for another.</summary>
public class PrefabSwitch : MonoBehaviour 
{
    /// <summary>The new object to instantiate in place of the old object.</summary>
    public GameObject newPrefab;
    /// <summary>The old objects, intended to be swapped out for iterations of 
    /// the new object.</summary>
    public GameObject[] oldGameObjects;
    /// <summary>The string tag to use when replacing objects by tag.</summary>
    public string searchByTag;

    /// <summary>Swaps all the game objects in oldGameObjects for 
    /// a new newPrefab.</summary>
    public void SwapAllByArray()
    {
        // Store a boolean to detect if we intend to swap this game object.
        bool swappingSelf = false;

        // For each game object in the oldGameObjects array, 
        for (int i = 0; i < oldGameObjects.Length; i++)
        {
            // If the current game object is this game object, 
            if (oldGameObjects[i] == gameObject)
            {
                // Enable the flag to swap this game object at the end, so we
                // do not destroy it before the script an complete its task.
                swappingSelf = true;
            }
            else
            {
                // Else, we are not dealing with the game object local to this 
                // script, so we can swap the prefabs, immediately. 
                SwapPrefabs(oldGameObjects[i]);
            }
        }

        // If we have flagged the local game object to be swapped, 
        if (swappingSelf)
        {
            // Swap the local game object.
            SwapPrefabs(gameObject);
        }
    }

    /// <summary>Swaps all the game objects that use the tag <code>searchByTag</code>.
    /// If empty, we will use the tag of the local game object.</summary>
    public void SwapAllByTag()
    {
        // If searchByTag is null, 
        if (searchByTag == "")
        {
            // Set searchByTag to the tag of the local game object.
            searchByTag = gameObject.tag;
        }

        // Find all the game objects using the tag searchByTag, 
        // store them in our array, and proceed to swapping them.
        oldGameObjects = GameObject.FindGameObjectsWithTag(searchByTag);
        SwapAllByArray();
    }

    /// <summary>Swaps the desired oldGameObject for a newPrefab.</summary>
    /// <param name="oldGameObject">The old game object.</param>
    void SwapPrefabs(GameObject oldGameObject)
    {
        // Determine the rotation and position values of the old game object.
        // Replace rotation with Quaternion.identity if you do not wish to keep rotation.
        Quaternion rotation = oldGameObject.transform.rotation;
        Vector3 position = oldGameObject.transform.position;

        // Instantiate the new game object at the old game objects position and rotation.
        GameObject newGameObject = Instantiate(newPrefab, position, rotation);

        // If the old game object has a valid parent transform,
        // (You can remove this entire if statement if you do not wish to ensure your
        // new game object does not keep the parent of the old game object.
        if (oldGameObject.transform.parent != null)
        {
            // Set the new game object parent as the old game objects parent.
            newGameObject.transform.SetParent(oldGameObject.transform.parent);
        }

        // Destroy the old game object, immediately, so it takes effect in the editor.
        DestroyImmediate(oldGameObject);
    }
}

/// <summary>Custom Editor for our PrefabSwitch script, to allow us to perform actions
/// from the editor.</summary>
[CustomEditor(typeof(PrefabSwitch))]
public class PrefabSwitchEditor : Editor
{
    /// <summary>Calls on drawing the GUI for the inspector.</summary>
    public override void OnInspectorGUI()
    {
        // Draw the default inspector.
        DrawDefaultInspector();

        // Grab a reference to the target script, so we can identify it as a 
        // PrefabSwitch, instead of a simple Object.
        PrefabSwitch prefabSwitch = (PrefabSwitch)target;

        // Create a Button for "Swap By Tag",
        if(GUILayout.Button("Swap By Tag"))
        {
            // if it is clicked, call the SwapAllByTag method from prefabSwitch.
            prefabSwitch.SwapAllByTag();
        }

        // Create a Button for "Swap By Array", 
        if (GUILayout.Button("Swap By Array"))
        {
            // if it is clicked, call the SwapAllByArray method from prefabSwitch.
            prefabSwitch.SwapAllByArray();
        }
    }
}

Replace By Tag

Replacing game objects by tag seems to be the most viable option, short of manually selecting the group of game objects you wish to swap out. If the set of game objects you are swapping out are all of the same prefab, replacing by tag is even easier.

First, you want to make sure that all of the targeted objects have the same tag. If needs be, you can make a temporary tag, to specifically mark the objects you wish to swap. You can apply this tag to the prefab of the old objects, and simply update it to impact all of them. Keep in mind that only the game objects you intend to swap should use this tag; the script will target all game objects using the given tag.

Without having to specify a tag, the script swaps out all cubes for spheres, using the original spheres tag.

Replace By Array

Replacing by array still requires a small amount of manual work, but allows you to quickly select a group of game objects, and immediately swap them out. This method is especially useful, as it allows you to quickly select the desired group, and is more reliable in that you confirm exactly which objects will be affected.

Note that you can select a group of objects and drag them on to a public array, to add them to the list as shown, below. If you drag additional objects on to the array in the same way, where there are already objects in the array, the new objects will simply be added to the array, along with the original objects that were already there.

Also note that you can click on the padlock icon, at the top right corner of the inspector, to lock that view. If you do not do this, selecting your group of old game objects will take focus away from the selected object. This is especially annoying when the selected object was the container for your script, and in taking focus away, you are unable to drop your selection on to the scripts public array.

By manually constructing the "old game objects" array, you can quickly assert and confirm the objects you wish to swap out.

\$\endgroup\$
3
  • \$\begingroup\$ Would be great if someone explains how to actually use it. Attaching to a gameobject like you would a regular script runs into "The script is an editor script," error. \$\endgroup\$
    – Battlefury
    Dec 15, 2019 at 12:38
  • \$\begingroup\$ For anyone interested. 1) Make an "Editor" folder in "Assets" and paste the code there splitting the two classes into two file say PrefabSwitch .cs and PrefabSwitchEditor.cs. 2) Wait for unity to create the Editor project (automatically), if not done already. 3) Add the PrefabSwitch script to any GO and find additional UI in the Inspector. \$\endgroup\$
    – Battlefury
    Dec 17, 2019 at 1:49
  • \$\begingroup\$ @Shoaib I can not speak for how you have your environment set up, but I have just confirmed that this all works as of the latest version. For anyone else using this answer, do not follow Shoaib's instructions unless you are familiar with Editor scripts (his suggestion is cleaner, but can be more confusing if you havn't worked with editor scripts, before). The entire script works as is as a Unity GameObject. Here is a link of the screenshots I took after successfully replacing gameObjects as per my original answer: imgur.com/rrRHL0F Unity version 2019.3.0b4 \$\endgroup\$
    – Gnemlock
    Dec 17, 2019 at 22:12
4
\$\begingroup\$

This will be an unusual way to go about it, because you don't want to script it. It will still take some time, but it's better than doing it one by one, and it should work as well as you want it to.

  1. Select all the game objects you want to change.

  2. Right click on one of the game objects while they are all selected, select "3D Object", and select any of the options.

It does not matter what object you choose. I have selected "3D Object > Cylinder".

  1. Place a copy your prefab in the scene, and then copy it with ctrl + c. Select one of the newly made child objects and paste the prefab with ctrl + v. Rinse and repeat until each of the new child objects has a copy of your prefab attached.

    As I did not have any other game objects between my new game objects, in the hierarchy, I was able to quickly move between each game object by pressing the key, twice. If this is the case, for you, you should be able to repeat the pattern of (, , ctrl+v). Remember that you have to paste the prefab on the child game objects; not the parents.

  2. Search for the prefab by name, and select them all. Set their coordinates to (0, 0, 0). This will set them to the exact same position as the parent game objects.

By setting the local position of the children game objects to (0, 0, 0), we see that they align with the position of their respective parent game objects.

  1. Clear the search result from the search bar by selecting the X. This will let you return to the full scene view, while still keeping all of those game objects selected. Drag and drop the selected game objects on to the scene name, which should remove them as parents from the original game objects.

Following the exact directions of step 5, we can return to the regular hierarchy view with all of our searched game objects still selected.

  1. Remove the original game objects. If you did everything right, your new objects should be where you wanted them to be, and the old ones should be gone.

As an end result, we have replaced all of our old game objects with a new game object.

\$\endgroup\$
2
  • \$\begingroup\$ For your step 5, where you remove the parent connection, you clearly describe the correct way to do it; however, you refer to the image in a way that suggests that this has already been done, in what the image is showing. You later make reference to 'now we can delete the cubes'. I think you may have captured this image prematurely, as you have not done anything to remove the parent connection, at this stage. This might confuse users, who follow your directions to the letter, but notice your diagrams conflicting with what they are seeing. \$\endgroup\$
    – Gnemlock
    Dec 13, 2016 at 1:21
  • \$\begingroup\$ Yep, my first attempt at an answer (well in december, it's 5th(?) overall). Not my proudest work. I am trying harder though :D \$\endgroup\$ Dec 13, 2016 at 7:13
1
\$\begingroup\$

Yes, Unity's inspector panel allows you to copy components from one GameObject and then paste them on another, by clicking on the cog icon at the top right of the component.

In your case, you want to copy the Transform component (by default, the first component).

See images below for visual reference.

This is how you copy a component enter image description here

\$\endgroup\$
3
  • \$\begingroup\$ My question is not related to scripting. Is it possible to do this in the editor? \$\endgroup\$
    – noev
    Dec 1, 2016 at 21:35
  • \$\begingroup\$ @noev My bad. I'll edit the post with how to do this from the editor. \$\endgroup\$ Dec 1, 2016 at 21:41
  • 1
    \$\begingroup\$ As a manual procedure, this works. Keep in mind that this requires you to re-iterate the procedure 100 times. \$\endgroup\$
    – Gnemlock
    Dec 1, 2016 at 22:36
1
\$\begingroup\$

If the top level gameObject of your prefabs serves merely as a container for the components of the prefab, then you can try the following:

  • Create an new instance of PrefabA ('PrefabA_New')and PrefabB on the same position (eg. 0,0,0).
  • Copy the contents of PrefabB's container gameObject, into the container of PrefabA_New, on the same level as the original contents of PrefabA_New. Unity will tell you that this will break the prefab. Accept.
  • Delete PrefabA_New's original content (do not delete PrefabB's content that you dragged into PrefabA_New).
  • Click 'Apply' on PrefabA_New so that it updates PrefabA. This will cause all the other instances of PrefabA to be the same as PrefabA_New (Which, in effect, is the same as PrefabB).

You can then proceed to delete PrefabB and PrefabA_New.

I hope this works. Good luck!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .