Breaking connection from gameObject to prefab for good.

Hi there!

Pretty basic question, but I can’t seem to find an answer in the forums and documentation:

Is there a way to break the connection from a GameObject in a scene to the prefab in the asset database for good? To make Unity forget that it once was an instance of a prefab? No more apply button and no more information about it via the AssetDatabase class methods?

thanks,
vivien

Don’t know about the Asset database, but to break prefab status,
try adding or removing a component such as the mesh collider to/from the object.

I ended up using a script to mass remove mesh colliders from
a lot of object that were parented to an empty rather effortlessly.

The hard part was manually adding mesh colliders onto them all again. :smile:

also please support this idea @ unity feedback:
http://feedback.unity3d.com/forums/15792-unity/suggestions/1614601-create-destroy-prefab-s-under-game-object-menu :wink:

Hi there!
Thanks for the response. I meant something a little different. To clarify:
Yes, breaking the link is quite easy. The blue text turns white (or black, in case you use Unity’s bright interface) and the object becomes a “broken prefab”. It looks like a simple game object in the hierarchy, but if you select it you get those 3 “Select”, “Revert” and “Apply” buttons at the top of the inspector to reconnect it to its prefab.
I want to go a little further than that. I want the prefab to become a simple game object again, without the apply and reconnect buttons.

Hi there. The problem just came up once again and so I thought about bumping this thread :wink:

I am also interested in this, so bump again.

Been looking for a solution to this for a while too. Hey Unity, how about a new button in inspector to “Remove Link” or something?

This works - I’ve tried it. However be warned that it will active gameObjects and their children. So what I did was store the list of active values for the whole hierarchy and then reapply the active values on the clone

string name = prefabedGO.name;
Transform parent = prefabedGO.transform.parent;

// unparent the GO so that world transforms are preserved
prefabedGO.transform.parent = null;

// clears prefab link
GameObject unprefabedGO = (GameObject)Object.Instantiate(prefabedGO);

// assigned reverted values
unprefabedGO.name = prefabedGO.name;
unprefabedGO.active = prefabedGO.active;

// remove old
DestroyImmediate(prefabedGO); // or this could just hide the old one .active = false;

// reparent clone
unprefabedGO.transform.parent = parent;
1 Like

I appear to be getting errors because of prefabs not being permanently breaking the connection.

My project had 2 prefabs with multiple elements in them. I only needed 1 prefab with some elements from each. So I dragged one into the scene, then broke the prefab. I then dragged the other in and broke that prefab. I moved the elements I wanted from one prefab into the other, then re-established the prefab on that one, and deleted the unused prefab in the Project view for the other.

That should be fine, but I am getting errors such as:

I have also edited several other prefabs, and they all appear to be corrupt now. I have submitted a bug about this before. Unity doesn’t appear to like elements from one prefab being used in another. Breaking a prefab instance isn’t enough to stop this. I’m using Unity 3.5.3.

It seems the entire ‘Prefabs’ part of unity is buggy. I am also having the problem where “Break Prefab Instance” doesn’t actually break the instance from the prefab, it just changes the color of the label in hierarchy.
Further more, if I duplicate a prefab, break instance, rename, and create prefab with ‘new’ object, I now have two prefabs that get updated when I click the ‘Apply’ button. This is stupid. if were stuck with ‘duplicate’ creating linked objects, then there should also be an option to ‘duplicate’ as unlinked objects. or full copy. Maybe I’ll make that a feature request…

I concur. This is a big unnecessary headache. When I break a prefab instance I want it completely and totally broken. Otherwise it leads to all sorts of nightmares if ‘broken’ prefabs are accidently reconnected etc.

Same problem here. WTF

if you delete the prefab in the Project tab, and then select the object in Hierarchy tab, click GameObject>Break Prefab Instance. the object will become a GameObject without connection from the old prefab.

if you don’t want to lost your old prefab, just use that object to make a new prefab, and then delete the new prefab.

2 Likes

why don’t you instantiate the prefab? that should give you “just” the gameobject with no connection.

This won’t help if you already have an instance whose connection you want broken (particularly if you’ve made instance-level changes across multiple components/children).

At any rate, here’s the solution I came up with. Hacky, but works well with no erratic behavior that I’ve been able to tell. Basically, you just create a temporary dummy prefab to connect the GameObject to, which you can then delete in order to have a total break.

Obviously, you should name this prefab something that doesn’t conflict with an existing one.

GameObject disconnectingObj;
PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
PrefabUtility.ReplacePrefab(disconnectingObj, prefab, ReplacePrefabOptions.ConnectToPrefab);
PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
AssetDatabase.DeleteAsset("Assets/dummy.prefab");

The one idiosyncracy is that if the GameObject in question is selected in the editor, a “SELECT” button will remain at the top of the inspector. It goes away if you deselect and reselect the object, and if you click it, it just deslects the object. Doesn’t seem to cause any problems.

Hope this helps!

1 Like

First, thanks AaronBiddlecom !

This code resolves your minor issue

GameObject disconnectingObj = Selection.activeGameObject;
Selection.activeGameObject = null;
PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
PrefabUtility.ReplacePrefab(disconnectingObj, prefab, ReplacePrefabOptions.ConnectToPrefab);
PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
AssetDatabase.DeleteAsset("Assets/dummy.prefab");
Selection.activeObject = disconnectingObj;
2 Likes

Thanks a lot ddvgames! That’s what I looking for.

I managed to break a prefab connection without deleting any existing prefabs by :

  1. Select object in hierarchy. Goto GameObject break prefab instance
  2. Drag object into project panel to create new prefab
  3. Delete the new prefab
  4. Select object in hierarchy. Goto GameObject break prefab instance
5 Likes

I made it into a scriptable wizard!

Simply place this in an appropriately named class in the editor folder.

using UnityEditor;
using UnityEngine;

public class BreakPrefabWizard : ScriptableWizard
{
    [MenuItem("GameObject/Break Prefab Instance Definitive")]
    static void CreateWizard()
    {
        GameObject disconnectingObj = Selection.activeGameObject;
        Selection.activeGameObject = null;
        PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
        Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
        PrefabUtility.ReplacePrefab(disconnectingObj, prefab, ReplacePrefabOptions.ConnectToPrefab);
        PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
        AssetDatabase.DeleteAsset("Assets/dummy.prefab");
        Selection.activeObject = disconnectingObj;
    }
}

I decided to actually spend some time making it better, so here’s a full editor suite.

It feature undo, context menu items on components and in the hierarchy tab, as well as items in the GameObject menu. All those items disable themselves if no prefabs are selected.

using UnityEditor;
using UnityEngine;
using System.Linq;

public static class PrefabBreakMenuItems
{
  #region MENU_ITEMS

  /// <summary>
  /// Breaks the prefab connection of every selected object and delete it permanently.
  /// </summary>
  [MenuItem("GameObject/Break Prefab Instance Definitive %&b", false, 29)]
  [MenuItem("CONTEXT/Object/Break Prefab Instance Definitive", false, 301)]
  static void MenuBreakInstanceDefinitive()
  {
  GameObject[] breakTargets = Selection.gameObjects;
  Selection.activeGameObject = null;
  BreakInstancesDefinitive(breakTargets);
  Selection.objects = breakTargets;
  }

  /// <summary>
  /// Breaks the prefab connection of every selected object, but leaves the "Select - Revert - Apply" buttons.
  /// </summary>
  [MenuItem("GameObject/Break Prefab Instance", false, 28)]
  [MenuItem("CONTEXT/Object/Break Prefab Instance", false, 300)]
  static void ContextBreakInstance(MenuCommand command)
  {
  GameObject[] breakTargets = Selection.gameObjects;
  Selection.activeGameObject = null;
  BreakInstances(breakTargets);
  Selection.objects = breakTargets;
  }

  /// <summary>
  /// Checks if any elements of the selection contain prefabs.
  /// </summary>
  [MenuItem("CONTEXT/Object/Break Prefab Instance", true)]
  [MenuItem("CONTEXT/Object/Break Prefab Instance Definitive", true)]
  [MenuItem("GameObject/Break Prefab Instance", true)]
  [MenuItem("GameObject/Break Prefab Instance Definitive %&b", true)]
  static bool PrefabCheck()
  {
  GameObject[] goSelection = Selection.gameObjects;

  return (goSelection.Any(x => PrefabUtility.GetPrefabParent(x)));
  }

  #endregion

  #region LOGIC

  /// <summary>
  /// Breaks the prefab connections of a list of GameObject and delete them permanently.
  /// Records an undo.
  /// </summary>
  public static void BreakInstancesDefinitive(GameObject[] targets)
  {
  Undo.RegisterCompleteObjectUndo(targets, "Breaking multiple prefab instances definitively");

  Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
  foreach (var target in targets)
  {
  PrefabUtility.ReplacePrefab(target, prefab, ReplacePrefabOptions.ConnectToPrefab);
  PrefabUtility.DisconnectPrefabInstance(target);
  }
  AssetDatabase.DeleteAsset("Assets/dummy.prefab");

  Undo.RecordObjects(targets, "Breaking multiple prefab instances definitively");
  }


  /// <summary>
  /// Breaks the prefab connection of a single GameObject and delete it permanently.
  /// Records an undo.
  /// </summary>
  public static void BreakInstanceDefinitive(GameObject target)
  {
  Undo.RegisterCompleteObjectUndo(target, "Breaking single prefab instance definitively");

  Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
   
  PrefabUtility.ReplacePrefab(target, prefab, ReplacePrefabOptions.ConnectToPrefab);
  PrefabUtility.DisconnectPrefabInstance(target);

  AssetDatabase.DeleteAsset("Assets/dummy.prefab");
  }

  /// <summary>
  /// Breaks the prefab connections of a list of GameObject, but leaves the "Select - Revert - Apply" buttons.
  /// Records an undo.
  /// </summary>
  public static void BreakInstances(GameObject[] targets)
  {
  Undo.RegisterCompleteObjectUndo(targets, "Breaking multiple prefab instances");
   
  foreach (var target in targets)
  {
  PrefabUtility.DisconnectPrefabInstance(target);
  }
  }

  /// <summary>
  /// Breaks the prefab connection of a single GameObject, but leaves the "Select - Revert - Apply" buttons.
  /// Records an undo.
  /// </summary>
  public static void BreakInstance(GameObject target)
  {
  Undo.RegisterCompleteObjectUndo(target, "Breaking single prefab instance");
  PrefabUtility.DisconnectPrefabInstance(target);
  }

  #endregion
}

2474382–170603–PrefabBreakMenuItems.cs (4.05 KB)

5 Likes

I found an easy way to deal with this stupid problem. Drag the gameobject into the assets folder to turn it into a prefab, thus forgetting about the old broken prefab connection. Then delete the new prefab, leaving the gameobject with a ‘missing’ prefab. Finally, select that gameobject and click ‘GameObject’ on the top menu and select ‘Break Prefab Instance’.