unity-game-engineaugmented-reality

How to fix destroy method in Unity AR


After I attempt to destroy a prefab after a delay, it destroys the prefab immediately with no delay. I am using the UnityEngine.Object.Destroy method. I tried using coroutines as well and it did not work.

I am a high school student trying to figure this out, so sorry if this seems like a dumb question.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using System;
 
 
[RequireComponent(typeof(ARTrackedImageManager))]
public class PlaceTrackedImages : MonoBehaviour
{
    // Reference to AR tarcked image manager component
    private ARTrackedImageManager _trackedImagesManager;
    // List of prefabs to instaniate
    public GameObject[] ArPrefabs;
    // Dictionary array of created prefabs
    private readonly Dictionary<string, GameObject> _instantiatedPrefabs = new Dictionary<string, GameObject>();
 
    private void Awake()
    {
        //Cache a reference to the Tarcked IMage Manager component
        _trackedImagesManager = GetComponent<ARTrackedImageManager>();
    }
 
    private void OnEnable()
    {
        // Attavh event handler when tarcked images change
        _trackedImagesManager.trackedImagesChanged += OnTrackedImagesChanged;
    }
 
    private void OnDisable()
    {
        // Remove event handler
        _trackedImagesManager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
 
    //  Event Handler
    private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        // Loop through all new tracked images that have been detected
        foreach (var trackedImage in eventArgs.updated)
        {
            // Get the name of the reference image
            var imageName = trackedImage.referenceImage.name;
            // Loop over the array of prefabs
            foreach (var curPrefab in ArPrefabs)
            {
                // Check whether this prefab matches the tracked image name, and that the prefab hasn't already been created
                if (string.Compare(curPrefab.name, imageName, StringComparison.OrdinalIgnoreCase) == 0 && !_instantiatedPrefabs.ContainsKey(imageName))
                {
                    // Instantiate the prefab, parenting it to the ARTrackedImage
                    var newPrefab = Instantiate(curPrefab, trackedImage.transform);
                    // Add the created prefab to the array
                    _instantiatedPrefabs[imageName] = newPrefab;
                }
            }
        }
 
        // For all prefabs that have been created so far, set them active or not depending on wehter their corresponding image is currently being tracked
        foreach (var trackedImage in eventArgs.updated)
        {
            _instantiatedPrefabs[trackedImage.referenceImage.name].SetActive(trackedImage.trackingState == TrackingState.Tracking);
        }
        // If the AR subsystem has given up looking for a tracked image
        foreach (var trackedImage in eventArgs.removed)
        {
            // Destroy its prefab after 10 second delay
            Destroy(_instantiatedPrefabs[trackedImage.referenceImage.name],10f);
            // Remove instance from the array
            _instantiatedPrefabs.Remove(trackedImage.referenceImage.name);
        }
    }
}

My trouble is in line 68 when I call the destroy method. Thanks!


Solution

  • It looks like you may be mistakenly interpreting the destruction of your instantiated object as being a result of your call to Destroy on line 68 - when in reality the destruction is occurring because the ARTrackedImageManager is destroying the ARTrackedImage itself - immediately after sending the 'removed' event.

    As your instantiated object is parented to the ARTrackedImage, it is destroyed as soon as the ARTrackedImage itself is destroyed, meaning your own call to Destroy is essentially superseded:

    var newPrefab = Instantiate(curPrefab, trackedImage.transform);
    

    To prevent the automatic destruction of your instantiated object, you can set ARTrackedImage.destroyOnRemoval to false. This will mean that you need to manually destroy the ARTrackedImage gameObject, rather than just your own instantiated gameObject - but it should give the results you need.