Unity AR中Destroy延迟销毁失效问题排查求助
Unity AR延迟销毁预制体失效问题解决
问题根源
- 父物体连带销毁:你将预制体实例化后挂载在
ARTrackedImage的Transform下,当AR系统触发removed事件时,Unity会立即销毁该ARTrackedImage对应的GameObject,其所有子物体(包括你的预制体)会被连带销毁,导致你设置的延迟销毁参数完全失效。 - 字典引用过早移除:调用
Destroy后立刻从字典中移除预制体引用,虽不直接导致立即销毁,但会丢失实例追踪状态,后续逻辑易出问题。
修复方案
- 将预制体从
ARTrackedImage的Transform下脱离,避免父物体销毁时被连带销毁; - 使用协程控制延迟销毁顺序,确保销毁完成后再移除字典中的引用。
修改后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.ARFoundation; using UnityEngine.XR.ARSubsystems; using System; [RequireComponent(typeof(ARTrackedImageManager))] public class PlaceTrackedImages : MonoBehaviour { private ARTrackedImageManager _trackedImagesManager; public GameObject[] ArPrefabs; private readonly Dictionary<string, GameObject> _instantiatedPrefabs = new Dictionary<string, GameObject>(); private void Awake() { _trackedImagesManager = GetComponent<ARTrackedImageManager>(); } private void OnEnable() { _trackedImagesManager.trackedImagesChanged += OnTrackedImagesChanged; } private void OnDisable() { _trackedImagesManager.trackedImagesChanged -= OnTrackedImagesChanged; } private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs) { // 处理新增/更新的追踪图像 foreach (var trackedImage in eventArgs.updated) { var imageName = trackedImage.referenceImage.name; foreach (var curPrefab in ArPrefabs) { if (string.Compare(curPrefab.name, imageName, StringComparison.OrdinalIgnoreCase) == 0 && !_instantiatedPrefabs.ContainsKey(imageName)) { var newPrefab = Instantiate(curPrefab, trackedImage.transform); _instantiatedPrefabs[imageName] = newPrefab; } } } // 设置预制体激活状态 foreach (var trackedImage in eventArgs.updated) { if (_instantiatedPrefabs.TryGetValue(trackedImage.referenceImage.name, out var prefab)) { prefab.SetActive(trackedImage.trackingState == TrackingState.Tracking); } } // 处理移除的追踪图像 foreach (var trackedImage in eventArgs.removed) { var imageName = trackedImage.referenceImage.name; if (_instantiatedPrefabs.TryGetValue(imageName, out var prefab)) { // 将预制体从ARTrackedImage父物体下脱离 prefab.transform.SetParent(null); // 启动协程延迟销毁并移除字典引用 StartCoroutine(DelayedDestroyAndRemove(imageName, prefab, 10f)); } } } private IEnumerator DelayedDestroyAndRemove(string imageName, GameObject prefab, float delay) { yield return new WaitForSeconds(delay); Destroy(prefab); _instantiatedPrefabs.Remove(imageName); } }
额外优化点
- 新增
TryGetValue判断,避免字典键不存在时抛出空引用异常; - 协程方法明确分离延迟销毁和字典移除逻辑,保证执行顺序正确。
内容的提问来源于stack exchange,提问作者syskhill
相关产品推荐
相关产品推荐

