Почему при замене игрового объекта префабом префаб позиция находится немного назад, а не точно в позиции игрового объекта? - PullRequest
0 голосов
/ 12 октября 2019

Это код для замены:

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();
    }
}

Я выбираю эту дверь, дверь находится внутри космической станции, и дверь является дочерней для другого игрового объекта, а другой игровой объект также является дочерним:

Door to replace

Тогда у меня есть сборный домик, я хочу заменить его дверью: сборный домик - это та же дверь, я только что поменял две двери в середине, сделалони в красном, но сборный - просто дверь, как на первом скриншоте. Масштабирование того же размера:

Prefab to place instead the door

Затем при замене сборного элемента находится немного назад от того места, где была дверь, но в инспекторе я вижута же позиция, что и у двери:

Replaced prefab

Теперь сборный дом расположен далеко сзади в комнате. Если я изменю положение и поворот в моем коде на локальный, то префаб будет располагаться намного вперед. Он никогда не будет располагаться на месте двери.

Я пробовал другие сценарии замены, все они дают одинаковые результаты. Я ничего не менял в сборном (сборный - это дверь), только добавляю эти цвета.

1 Ответ

1 голос
/ 12 октября 2019

Это происходит потому, что центр префаба отличается от центра исходного объекта.

Вы можете перецентрировать объект, поместив его в пустой объект и переместив его в локальное положение этого объекта.

Затем вы можете использовать этот объект в качестве префаба, который будет на сцене.

Надеюсь, это помогло

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...