Есть ли способ уничтожить / заменить GameObject, который находится внутри или частью Prefab-экземпляра? - PullRequest
0 голосов
/ 05 апреля 2019

Исключение

Я получаю исключение в редакторе:

InvalidOperationException: уничтожение GameObject внутри экземпляра Prefab недопустимо.

Тогда мне нужно пойти вручную, чтобы открыть префаб и удалить из него игровой объект. Но есть ли способ сделать это с помощью автоматического сценария?

Это мой скрипт для замены игровых объектов на префаб. Единственное изменение, которое я сделал для префаба, это взятие gmeobject и добавление к нему некоторых цветов и текстур, все сценарии и другие вещи одинаковые.

Я пытаюсь заменить все двери в сцене на сборный, который также является дверью только с некоторыми цветами и текстурой.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class PrefabReplace : EditorWindow
{
    [SerializeField] private GameObject prefab;
    private bool selectionChanged;
    private string objectsToSearch = "";
    private List<GameObject> foundObjects = new List<GameObject>();
    private List<GameObject> duplicatedObjects = new List<GameObject>();
    private bool searched = false;
    private int count = 0;
    private int countChilds = 0;
    private bool countChildren = false;
    private GUIStyle guiStyle = new GUIStyle(); //create a new variable
    private Texture timage;

    [MenuItem("Tools/Prefab Replace")]
    static void CreateReplaceWithPrefab()
    {
        int width = 340;
        int height = 300;

        int x = (Screen.currentResolution.width - width) / 2;
        int y = (Screen.currentResolution.height - height) / 2;

        GetWindow<PrefabReplace>().position = new Rect(x, y, width, height);
    }

    private void OnGUI()
    {
        Texture oo = null;
        Texture texture = (Texture)oo;
        //EditorGUI.DrawTextureTransparent(new Rect(10, 10, 20, 20), timage);

        guiStyle.fontSize = 20; //change the font size
        Searching();
        GUILayout.Space(50);
        Replacing();
    }

    private void Searching()
    {
        GUI.Label(new Rect(10, 20, 150, 20), "Search by name", guiStyle);
        objectsToSearch = GUI.TextField(new Rect(90, 60, 150, 20), objectsToSearch, 25);

        if (objectsToSearch != "")
        {
            GUI.enabled = true;
        }
        else
        {
            GUI.enabled = false;
        }
        GUILayout.Space(40);
        if (GUILayout.Button("Search"))
        {
            foundObjects = new List<GameObject>();
            duplicatedObjects = new List<GameObject>();
            countChildren = true;
            countChilds = 0;
            count = 0;

            foreach (GameObject gameObj in GameObject.FindObjectsOfType<GameObject>())
            {
                if (gameObj.name == objectsToSearch)
                {
                    count += 1;
                    foundObjects.Add(gameObj);
                    Transform[] childs = gameObj.GetComponentsInChildren<Transform>();
                    foreach (Transform go in childs)
                    {
                        foundObjects.Add(go.gameObject);
                    }
                }
            }

            if (foundObjects.Count > 0)
            {
                searched = true;
            }
            else
            {
                searched = false;
            }
        }

        GUI.enabled = true;
        if (count > 0)
            GUI.TextField(new Rect(90, 85, 60, 15), count.ToString(), 25);

        if (foundObjects.Count > 0 && countChildren == true)
        {
            for (int i = 0; i < foundObjects.Count; i++)
            {
                if (foundObjects[i].transform.childCount > 0)
                {
                    countChilds += foundObjects[i].transform.childCount;
                }
            }

            countChildren = false;
        }
        GUI.enabled = true;
        if (countChilds > 0)
            GUI.TextField(new Rect(90, 105, 60, 15), countChilds.ToString(), 25);

        GUILayout.Space(100);

        if (foundObjects.Count > 0)
            EditorGUILayout.LabelField("Test");
    }

    private void Replacing()
    {
        GUILayout.Space(20);
        GUILayout.BeginVertical(GUI.skin.box);
        GUILayout.Label("Replacing");
        GUILayout.Space(20);

        prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);

        var selection = Selection.objects.OfType<GameObject>().ToList();
        if (selectionChanged)
        {
            if (selection.Count == 0)
                GUI.enabled = false;

            for (var i = selection.Count - 1; i >= 0; --i)
            {
                var selectedObject = selection[i];
                if (prefab != null && selection.Count > 0 &&
                    selectedObject.scene.name != null
                    && prefab != PrefabUtility
                    .GetCorrespondingObjectFromSource(selectedObject))
                {
                    GUI.enabled = true;
                }
                else
                {
                    GUI.enabled = false;
                }
            }
        }
        else
        {
            GUI.enabled = false;
        }

        if (GUILayout.Button("Replace"))
        {
            InstantiatePrefab(selection);
            selectionChanged = false;
        }

        GUILayout.Space(10);
        GUI.enabled = true;
        EditorGUILayout.LabelField("Selection count: " + Selection.objects.OfType<GameObject>().Count());

        GUILayout.EndVertical();
    }

    private void OnInspectorUpdate()
    {
        Repaint();
    }

    private void OnSelectionChange()
    {
        selectionChanged = true;
    }

    private void InstantiatePrefab(List<GameObject> selection)
    {
        if (prefab != null && selection.Count > 0)
        {
            for (var i = selection.Count - 1; i >= 0; --i)
            {
                var selected = selection[i];
                Component[] components = selected.GetComponents(typeof(MonoBehaviour));
                if (components.Length == 0)
                {
                    SceneManager.SetActiveScene(SceneManager.GetSceneByName(selected.scene.name));

                    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.localPosition = selected.transform.localPosition;
                    newObject.transform.localRotation = selected.transform.localRotation;
                    newObject.transform.localScale = selected.transform.localScale;
                    newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
                    Undo.DestroyObjectImmediate(selected);
                }
            }
        }
    }
}

Все двери были заменены в порядке, но дверь на скриншоте - единственная, которая является частью сборного экземпляра.

1 Ответ

0 голосов
/ 05 апреля 2019

PrefabUtility.LoadPrefabContents ()

Этот метод выполняет следующие действия:

Загружает актив Prefab по указанному пути в изолированную сцену и возвращает корневой GameObject префаба.

Вы можете использовать это, чтобы получить содержимое префаба и изменить его напрямую вместо того, чтобы просматривать экземпляр префаба. Это полезно для пакетных операций.

Это позволит вам изменить префаб так, как вы хотите:

После того, как вы изменили префаб, вы должны записать его обратно, используя SaveAsPrefabAsset, а затем вызвать UnloadPrefabContents, чтобы освободить префаб и изолированную сцену из памяти.

Вы должны снова сохранить его в исходном префабе и перезаписать ваши изменения.

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