游戏关闭时如何重置预制体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
相关产品推荐
相关产品推荐

