Daniel Lip
Daniel Lip

Reputation: 11319

Why when replacing a gameobject with prefab the prefab position is a bit to the back and not exactly on the gameobject position?

This is the code for replacing :

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class SaveTransformsInfo : EditorWindow
{
    [SerializeField] private GameObject prefab;

    [MenuItem("Tools/Replace With Prefab")]
    static void CreateReplaceWithPrefab()
    {
        EditorWindow.GetWindow<SaveTransformsInfo>();
    }

    private void OnGUI()
    {
        prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);

        if (prefab == null || Selection.gameObjects.Length == 0)
        {
            GUI.enabled = false;
        }
        else
        {
            GUI.enabled = true;
        }
        if (GUILayout.Button("Replace"))
        {
            var selection = Selection.gameObjects;
            var parentGameobjects = CheckParents(selection);

#if UNITY_EDITOR
            UnityEditor.Selection.objects = parentGameobjects;
#endif

            for (var i = parentGameobjects.Length - 1; i >= 0; --i)
            {
                var selected = parentGameobjects[i];
                var prefabType = PrefabUtility.GetPrefabType(prefab);
                GameObject newObject;

                if (prefabType == PrefabType.Prefab)
                {
                    newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
                }
                else
                {
                    newObject = Instantiate(prefab);
                    newObject.name = prefab.name;
                }

                if (newObject == null)
                {
                    Debug.LogError("Error instantiating prefab");
                    break;
                }

                Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
                newObject.transform.parent = selected.transform.parent;
                newObject.transform.position = selected.transform.position;
                newObject.transform.rotation = selected.transform.rotation;
                newObject.transform.localScale = selected.transform.localScale;
                newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
                DestroyObjectInPrefab(selected.transform);
            }
        }

        if(GUILayout.Button("Get Info"))
        {
            TransformSaver.SaveTransform(null, Selection.gameObjects[0]);
        }

        GUI.enabled = false;
        EditorGUILayout.LabelField("Selection count: " + Selection.gameObjects.Length);
    }

    private GameObject[] CheckParents(params GameObject[] objects)
    {
        List<GameObject> parents = new List<GameObject>(objects.Length);
        Transform[] transforms = objects.Select(go => go.transform).ToArray();
        for (int objectIndex = 0; objectIndex < transforms.Length; objectIndex++)
        {
            if (!IsChildOfAny(transforms[objectIndex], transforms))
                parents.Add(transforms[objectIndex].gameObject);
        }

        return parents.ToArray();
    }

    private bool IsChildOfAny(Transform potentialChild, params Transform[] potentialParents)
    {
        for (int index = 0; index < potentialParents.Length; index++)
        {
            if (IsParentOf(potentialParents[index], potentialChild))
                return true;
        }
        return false;
    }

    private bool IsParentOf(Transform potentialParent, Transform potentialChild)
    {
        if (potentialChild.parent == null)
            return false;

        if (potentialChild.parent == potentialParent)
            return true;

        return IsParentOf(potentialParent, potentialChild.parent);
    }

    private void DestroyObjectInPrefab(Transform transform)
    {
        if (PrefabUtility.IsPartOfPrefabInstance(transform))
        {
            //if a part of a prefab instance then get the instance handle
            Object prefabInstance = PrefabUtility.GetPrefabInstanceHandle(transform);
            //destroy the handle
            if (prefabInstance != null)
            {
                Undo.DestroyObjectImmediate(prefabInstance);
            }
        }
        //the usual destroy immediate to clean up scene objects
        //DestroyImmediate(transform.gameObject, true);
        Undo.DestroyObjectImmediate(transform.gameObject);
    }

    private void OnSelectionChange()
    {
        Repaint();
    }
}

I'm selecting this door the door is inside a space station and the door is a child of another gameobject and the other gameobject is also child :

Door to replace

Then I have a prefab I want to replace it with the door : The prefab is the same door I just changed the two doors in the middle made them in red but the prefab is just a door like in thecfirst screenshot. Same size scaling :

Prefab to place instead the door

Then when making the replacing the prefab is places in a bit back from where the door was position but in the inspector I see same position as the door :

Replaced prefab

Now the prefab is positioned much to the back inside the room. If I change the position and rotation in my code to local then the prefab will be positioned to much forward. It will never position at the place of the door.

I tried other replace scripts all give the same result/s. I didn't change anything in the prefab(The prefab is a door) only add this colors.

Upvotes: 0

Views: 488

Answers (1)

Carlos Manuel
Carlos Manuel

Reputation: 86

This is happening because the center of the prefab is different than the original object's center.

You can recenter object by putting it in a empty object and moving it in the local position of that object.

Then you can use that object as the prefab that is going to be in the scene.

Hope it helped

Upvotes: 1

Related Questions