All these seem so overcomplicated. Here, I’ve taken and optimized it all to work based on what game objects you have selected, rather than having to individually drag an drop every object into an array object in the window… Enjoy.
using UnityEngine;
using UnityEditor;
using System.Collections;
public class ReplaceGameObjects : ScriptableWizard
{
public GameObject useGameObject;
[MenuItem ("Custom/Replace GameObjects")]
static void CreateWizard ()
{
ScriptableWizard.DisplayWizard("Replace GameObjects", typeof(ReplaceGameObjects), "Replace");
}
void OnWizardCreate ()
{
foreach (Transform t in Selection.transforms)
{
GameObject newObject = (GameObject)EditorUtility.InstantiatePrefab(useGameObject);
Transform newT = newObject.transform;
newT.position = t.position;
newT.rotation = t.rotation;
newT.localScale = t.localScale;
}
foreach (GameObject go in Selection.gameObjects)
{
DestroyImmediate(go);
}
}
}
This is a really useful script. Thanks to everyone who worked on it
There’s something I’ve been looking to to be able to do in Unity for years now. And this script comes the closest so far…
How hard would it be to automate this process a little more, so it could replace multiple DIFFERENT objects with DIFFERENT prefabs.
eg. I export an FBX from Max that contains hundreds of modular instanced objects (wall sections, foliage, etc). Import it into Unity and put it in the scene where you can see it still has all the individual objects as children under a game object. And I’ve already made all the prefab wall sections, foliage objects, etc.
Could I then run a script that looks at each child object, figures out which of my prefabs it matches. And then go through and replace them all. I could build whole levels in Max this way. It would be amazing!
The instances from Max have a unique number suffix, but other than that the name of each one could be used to find it’s replacement prefab.
Even better would be if I could put this script on an empty game object in the scene and use it like a manager so it can be told which fbx (or selection of fbx’s) from the Assets folder to source and then when you click go it basically runs through the process automatically leaving you with a whole lot of placed prefabs. It could maybe have an option to auto-update if it detects the fbx has been changed.
I would pay big money for this functionality if I saw it on the Asset Store.
Thank you so much guys! This script is a life saver!
Here, I also added a second class which replaces objects based on their name instead of based on selection. (I have thousands of instances of the same prefab, all with broken prefab-connection - but they all have the same name, so in a situation like this, this script is more handy)
public class BatchReplaceByName : ScriptableWizard
{
public GameObject NewType;
public string Name = "";
public bool MatchCase = false;
[MenuItem("Custom/Batch Replace By Name")]
static void CreateWizard()
{
var replaceGameObjects = ScriptableWizard.DisplayWizard <BatchReplaceByName>("Replace GameObjects", "Replace");
}
void OnWizardCreate()
{
GameObject[] allObjects = GameObject.FindObjectsOfType<GameObject>();
if (!MatchCase)
Name = Name.ToUpper ();
foreach(GameObject go in allObjects)
{
if((MatchCase ? go.name : go.name.ToUpper()) != Name)
continue;
GameObject newObject = (GameObject)PrefabUtility.InstantiatePrefab(NewType);
newObject.transform.parent = go.transform.parent;
newObject.transform.localPosition = go.transform.localPosition;
newObject.transform.localRotation = go.transform.localRotation;
newObject.transform.localScale = go.transform.localScale;
newObject.name = go.name;
UnityEngine.Object.DestroyImmediate(go);
}
}
}
Update from me- the API changed slightly for Unity 5 and this version should work with the new update. Anyone on Unity 4 or earlier will need the previous version.
using UnityEngine;
using UnityEditor;
using System.Collections;
// CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
// March 2010
//Modified by Kristian Helle Jespersen
//June 2011
//Modified by Connor Cadellin McKee for Excamedia
//April 2015
public class ReplaceGameObjects : ScriptableWizard
{
public bool copyValues = true;
public GameObject NewType;
public GameObject[] OldObjects;
[MenuItem("Custom/Replace GameObjects")]
static void CreateWizard()
{
var replaceGameObjects = ScriptableWizard.DisplayWizard <ReplaceGameObjects>("Replace GameObjects", "Replace");
replaceGameObjects.OldObjects = Selection.gameObjects;
}
void OnWizardCreate()
{
//Transform[] Replaces;
//Replaces = Replace.GetComponentsInChildren<Transform>();
foreach (GameObject go in OldObjects)
{
GameObject newObject;
newObject = (GameObject)PrefabUtility.InstantiatePrefab(NewType);
newObject.transform.parent = go.transform.parent;
newObject.transform.localPosition = go.transform.localPosition;
newObject.transform.localRotation = go.transform.localRotation;
newObject.transform.localScale = go.transform.localScale;
DestroyImmediate(go);
}
}
}
Added an option to keep the original objects’ name.
Improved field names and cleaned the code.
using UnityEngine;
using UnityEditor;
// CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
// March 2010
//Modified by Kristian Helle Jespersen
//June 2011
//Modified by Connor Cadellin McKee for Excamedia
//April 2015
//Modified by Fernando Medina (fermmmm)
//April 2015
public class ReplaceGameObjects : ScriptableWizard
{
public GameObject Prefab;
public GameObject[] ObjectsToReplace;
public bool KeepOriginalNames = true;
[MenuItem("Custom/Replace GameObjects")]
static void CreateWizard()
{
var replaceGameObjects = DisplayWizard<ReplaceGameObjects>("Replace GameObjects", "Replace");
replaceGameObjects.ObjectsToReplace = Selection.gameObjects;
}
void OnWizardCreate()
{
foreach (GameObject go in ObjectsToReplace)
{
GameObject newObject;
newObject = (GameObject)PrefabUtility.InstantiatePrefab(Prefab);
newObject.transform.SetParent(go.transform.parent, true);
newObject.transform.localPosition = go.transform.localPosition;
newObject.transform.localRotation = go.transform.localRotation;
newObject.transform.localScale = go.transform.localScale;
if (KeepOriginalNames)
newObject.transform.name = go.transform.name;
DestroyImmediate(go);
}
}
}