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

游戏关闭时如何重置预制体Tag?Inventory脚本问题求助

问题根源与解决方案

你遇到的问题核心是直接修改了预制体资产的Tag属性——Unity编辑器会将运行时对预制体资产的修改永久保存,所以退出游戏后Tag仍保持为"stored"。而OnApplicationQuit在编辑器停止运行时不一定能可靠触发,就算触发,也可能没正确定位到原始预制体来恢复Tag。

以下是几种解决思路,按推荐程度排序:

1. 用独立数据结构记录物品状态(最推荐)

放弃修改预制体Tag的做法,改用字典或自定义类来存储物品栏的预制体与数量对应关系,完全不触碰预制体的任何属性。

修改后的代码示例:

// 替换原来的StoredObj和ObjAmount列表
private Dictionary<GameObject, int> _inventoryDict = new Dictionary<GameObject, int>();
// 如果需要存储实例,再加一个列表
private List<GameObject> _storedInstances = new List<GameObject>();

public void AddObjInv(GameObject invObjPrefab, int amount)
{
    if (_inventoryDict.ContainsKey(invObjPrefab))
    {
        // 物品已存在,叠加数量
        _inventoryDict[invObjPrefab] += amount;
    }
    else
    {
        // 实例化物品到物品栏
        GameObject invObjInstance = Instantiate(invObjPrefab, 
            new Vector3(transform.position.x + 1.0f, transform.position.y, 0f), 
            Quaternion.identity, 
            this.transform);
            
        if (transform.localScale.x == 1)
        {
            invObjInstance.transform.localScale = new Vector3(-1, 1, 1);
        }
        
        invObjInstance.name = invObjPrefab.name;
        invObjInstance.SetActive(false);
        
        // 记录预制体与数量
        _inventoryDict.Add(invObjPrefab, amount);
        _storedInstances.Add(invObjInstance);
    }
}

这种方式彻底避免了修改预制体资产,逻辑更清晰,也不会出现持久化修改的问题。

2. 仅修改实例Tag,不碰预制体

如果你坚持用Tag标记,要确保永远只修改场景中实例的Tag,而非原始预制体。可以先判断传入的对象是否是预制体:

public void AddObjInv(GameObject invObj, int amount)
{
    // 判断是否是预制体资产
    bool isPrefab = PrefabUtility.IsPartOfPrefabAsset(invObj);
    
    // 用实例的Tag判断,而非预制体
    GameObject targetObj = isPrefab ? Instantiate(invObj).gameObject : invObj;
    
    if (targetObj.tag != "stored")
    {
        // 后续逻辑操作targetObj,而非原始预制体
        GameObject invObj2 = Instantiate(invObj, new Vector3(transform.position.x + 1.0f, transform.position.y, 0f), Quaternion.identity, this.transform);
        if (transform.localScale.x == 1)
        {
            invObj2.transform.localScale = new Vector3(-1, 1, 1);
        }
        invObj2.name = invObj.name;
        invObj2.SetActive(false);
        StoredObj.Add(invObj2);
        ObjAmount.Add(amount);
        targetObj.tag = "stored";
    }
    else
    {
        ObjAmount[StoredObj.IndexOf(targetObj)] += amount;
    }
}

但这种方式不如第一种简洁,且容易混淆预制体和实例的关系。

3. 编辑器模式下自动恢复预制体Tag(治标不治本)

如果一定要用修改预制体Tag的方式,可以在Editor脚本中监听播放状态变化,退出播放时自动重置预制体Tag:

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class PrefabTagResetter
{
    static PrefabTagResetter()
    {
        EditorApplication.playModeStateChanged += OnPlayModeChanged;
    }

    private static void OnPlayModeChanged(PlayModeStateChange state)
    {
        if (state == PlayModeStateChange.ExitingPlayMode)
        {
            // 遍历所有预制体,重置Tag
            string[] prefabPaths = AssetDatabase.GetAllAssetPaths();
            foreach (string path in prefabPaths)
            {
                GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (prefab != null && prefab.tag == "stored")
                {
                    prefab.tag = "Untagged"; // 替换为你预制体原来的Tag
                    EditorUtility.SetDirty(prefab);
                }
            }
            AssetDatabase.SaveAssets();
        }
    }
}
#endif

注意:这个脚本必须放在Editor文件夹下,且可能会误改其他预制体的Tag,仅作为临时解决方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:47:42