如何销毁预制件中的游戏对象?

时间:2020-02-15 07:37:25

标签: c# unity3d

我想使用ModifyPrefab方法,但不确定如何使用。 问题是当我销毁oldGameObject时:

DestroyImmediate(oldGameObject);

我在编辑器中遇到异常:

InvalidOperationException:不允许销毁Prefab实例内部的GameObject。

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

public class PrefabSwitch : MonoBehaviour
{
    /// <summary>The new object to instantiate in place of the old object.</summary>
    public GameObject newPrefab;
    /// <summary>The old objects, intended to be swapped out for iterations of 
    /// the new object.</summary>
    public GameObject[] oldGameObjects;
    /// <summary>The string tag to use when replacing objects by tag.</summary>
    public string searchByTag;

    /// <summary>Swaps all the game objects in oldGameObjects for 
    /// a new newPrefab.</summary>
    public void SwapAllByArray(GameObject[] objectsToSwap)
    {
        // Store a boolean to detect if we intend to swap this game object.
        bool swappingSelf = false;

        // For each game object in the oldGameObjects array, 
        for (int i = 0; i < oldGameObjects.Length; i++)
        {
            // If the current game object is this game object, 
            if (oldGameObjects[i] == gameObject)
            {
                // Enable the flag to swap this game object at the end, so we
                // do not destroy it before the script an complete its task.
                swappingSelf = true;
            }
            else
            {
                // Else, we are not dealing with the game object local to this 
                // script, so we can swap the prefabs, immediately. 
                SwapPrefabs(oldGameObjects[i]);
            }
        }

        // If we have flagged the local game object to be swapped, 
        if (swappingSelf)
        {
            // Swap the local game object.
            SwapPrefabs(gameObject);
        }
    }

    /// <summary>Swaps all the game objects that use the tag <code>searchByTag</code>.
    /// If empty, we will use the tag of the local game object.</summary>
    public void SwapAllByTag()
    {
        // If searchByTag is null, 
        if (searchByTag == "")
        {
            // Set searchByTag to the tag of the local game object.
            searchByTag = gameObject.tag;
        }

        // Find all the game objects using the tag searchByTag, 
        // store them in our array, and proceed to swapping them.
        oldGameObjects = GameObject.FindGameObjectsWithTag(searchByTag);
        SwapAllByArray(oldGameObjects);
    }

    /// <summary>Swaps the desired oldGameObject for a newPrefab.</summary>
    /// <param name="oldGameObject">The old game object.</param>
    void SwapPrefabs(GameObject oldGameObject)
    {
        // Determine the rotation and position values of the old game object.
        // Replace rotation with Quaternion.identity if you do not wish to keep rotation.
        Quaternion rotation = oldGameObject.transform.rotation;
        Vector3 position = oldGameObject.transform.position;

        // Instantiate the new game object at the old game objects position and rotation.
        GameObject newGameObject = Instantiate(newPrefab, position, rotation);

        // If the old game object has a valid parent transform,
        // (You can remove this entire if statement if you do not wish to ensure your
        // new game object does not keep the parent of the old game object.
        if (oldGameObject.transform.parent != null)
        {
            // Set the new game object parent as the old game objects parent.
            newGameObject.transform.SetParent(oldGameObject.transform.parent);
        }

        // Destroy the old game object, immediately, so it takes effect in the editor.
        DestroyImmediate(oldGameObject);
    }

    private void ModifyPrefab()
    {
        // Get the Prefab Asset root GameObject and its asset path.
        GameObject assetRoot = Selection.activeObject as GameObject;
        string assetPath = AssetDatabase.GetAssetPath(assetRoot);

        // Load the contents of the Prefab Asset.
        GameObject contentsRoot = PrefabUtility.LoadPrefabContents(assetPath);

        // Modify Prefab contents.
        contentsRoot.AddComponent<BoxCollider>();

        // Save contents back to Prefab Asset and unload contents.
        PrefabUtility.SaveAsPrefabAsset(contentsRoot, assetPath);
        PrefabUtility.UnloadPrefabContents(contentsRoot);
    }
}

1 个答案:

答案 0 :(得分:1)

这里对此进行了广泛讨论:https://forum.unity.com/threads/destroying-a-gameobject-inside-a-prefab-instance-is-not-allowed.555868/

这不完全是一个错误,而是PreFab系统实施带来的副作用。

最佳解决方案是:

if (UnityEditor.PrefabUtility.IsPartOfPrefabInstance(transform))

   UnityEditor.PrefabUtility.UnpackPrefabInstance(gameObject,
         UnityEditor.PrefabUnpackMode.Completely,
         UnityEditor.InteractionMode.AutomatedAction);

// Then I do DestroyImmediate();

这:

var rootGO = PrefabUtility.LoadPrefabContents(pathToMyPrefab);
// Destroy child objects or components on rootGO
PrefabUtility.SaveAsPrefabAsset(rootGO, pathToMyPrefab);
prefabUtility.UnloadPrefabContents(rootGO);