如何销毁属于预制件的游戏对象? [英] How can I destroy a gameobject that is part of a prefab?

查看:25
本文介绍了如何销毁属于预制件的游戏对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to use the ModifyPrefab method but not sure how. The problem is when I'm destroying the oldGameObject :

DestroyImmediate(oldGameObject);

我在编辑器中遇到异常:

I'm getting exception in the editor :

InvalidOperationException:不允许销毁预制实例内的游戏对象.

InvalidOperationException: Destroying a GameObject inside a Prefab instance is not allowed.

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

推荐答案

这里有大量讨论:https://forum.unity.com/threads/destroying-a-gameobject-inside-a-prefab-instance-is-not-允许.555868/

这不完全是错误,而是实施 PreFab 系统的副作用.

It is not exactly a bug, but a side effect from the implementation of the PreFab system.

最佳解决方案是:

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

这篇关于如何销毁属于预制件的游戏对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆