You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity编辑器:预制体变体删GameObject后无法正确保存的问题求助

解决方案

1. 加载预制体变体时保留预制体关联

不要在实例化后直接解包整个房间预制体——解包会切断它与基础预制体的关联,导致保存时无法被识别为变体。正确做法是直接实例化基础预制体或已有变体,保留预制体链接:

// 加载基础预制体并实例化(保留预制体关联)
GameObject roomInstance = PrefabUtility.InstantiatePrefab(baseRoomPrefab) as GameObject;
// 标记实例为已修改的预制体实例
PrefabUtility.SetPrefabInstanceStatus(roomInstance, PrefabInstanceStatus.Modified);

2. 修正Tile删除逻辑

不能直接用DestroyImmediate删除预制体实例中的GameObject,需根据Tile的来源(基础预制体自带/变体新增)分别处理:

  • 若Tile是基础预制体原有内容:用RevertPrefabInstance还原到基础状态,而非删除
  • 若Tile是变体新增内容:用预制体专用APIDeletePrefabInstanceGameObject删除

修改后的AttemptDeleteTile代码:

private void AttemptDeleteTile()
{
    Vector3 newPosition = tileEditorInputComponent.NewTilePosition;
    Tile existingTile = GetExistingTileAtNewPosition(newPosition);

    if (existingTile == null) return;

    GameObject tileObj = existingTile.gameObject;
    Object prefabSource = PrefabUtility.GetCorrespondingObjectFromSource(tileObj);

    if (prefabSource != null)
    {
        // Tile来自基础预制体,还原到基础状态
        PrefabUtility.RevertPrefabInstance(tileObj, InteractionMode.AutomatedAction);
    }
    else
    {
        // Tile是变体新增内容,用预制体API删除
        if (PrefabUtility.IsPartOfPrefabInstance(tileObj))
        {
            PrefabUtility.DeletePrefabInstanceGameObject(tileObj);
        }
        else
        {
            Object.DestroyImmediate(tileObj);
        }
    }
}

3. 正确保存预制体变体

保存时需确保房间实例仍与基础预制体保持关联,这样SaveAsPrefabAssetAndConnect才会创建/更新变体,而非覆盖基础预制体:

public static void SaveRoomPrefab(GameObject room, string regionName, GameObject baseRoomPrefab)
{
    string directoryPath = Path.Combine(RoomsPrefabPath, regionName);
    if (!Directory.Exists(directoryPath))
        Directory.CreateDirectory(directoryPath);

    string prefabPath = Path.Combine(directoryPath, room.name + ".prefab");

    if (File.Exists(prefabPath))
    {
        if (!EditorUtility.DisplayDialog("Prefab Already Exists",
                $"A prefab named {room.name} exists in {regionName}. Replace it?",
                "Yes", "No"))
            return;
    }

    GameObject existingPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
    if (existingPrefab != null && PrefabUtility.IsPrefabVariant(existingPrefab))
    {
        // 更新已有变体
        PrefabUtility.SavePrefabAsset(existingPrefab);
    }
    else
    {
        // 创建新变体,指定父预制体
        PrefabUtility.SaveAsPrefabAssetAndConnect(room, prefabPath, InteractionMode.UserAction, 
            new PrefabCreationOptions { PrefabVariant = true, ParentPrefab = baseRoomPrefab });
    }

    AssetDatabase.Refresh();
}

关键注意事项

  • 不要随意解包预制体实例,除非明确要切断与源预制体的关联
  • 所有对预制体实例的修改必须使用PrefabUtility系列API,而非普通的Destroy/Instantiate
  • 保存变体时必须指定父预制体,否则Unity会将其视为独立预制体

内容的提问来源于stack exchange,提问作者Ava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:17:46