Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Can't run my coroutine OnDestroy()?

Discussion in 'Scripting' started by brunoenvia, Nov 29, 2019.

  1. brunoenvia

    brunoenvia

    Joined:
    Aug 5, 2019
    Posts:
    94
    i am having this error when i try to run my coroutine

    Coroutine couldn't be started because the the game object 'Player' is inactive!

    why is this happening? thanks

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5. using UnityEngine.UI;
    6.  
    7. public class PlayerDeath : MonoBehaviour
    8. {
    9.     GetAudioSource audioSFX;
    10.     SceneLoader sceneLoader;  
    11.     [SerializeField] GameObject ball;
    12.     [SerializeField] ParticleSystem deathVFX;    
    13.     [SerializeField] Image loseScreen;
    14.     [SerializeField] Transform playerUI;
    15.     [SerializeField] float delayToShowScreen = 0.5f;
    16.  
    17.     private void Awake()
    18.     {
    19.            
    20.     }
    21.  
    22.     // Start is called before the first frame update
    23.     void Start()
    24.     {
    25.         audioSFX = FindObjectOfType<GetAudioSource>(); // find this object and reference it whenever the variable is used.
    26.         sceneLoader = FindObjectOfType<SceneLoader>();      
    27.     }
    28.  
    29.     // Update is called once per frame
    30.     void Update()
    31.     {
    32.        
    33.     }
    34.  
    35.      public void OnTriggerEnter(Collider other)
    36.     {
    37.         if (other.gameObject.tag == "DeathTrigger")
    38.         {
    39.             PlayerDying();          
    40.         }
    41.     }
    42.  
    43.     private void OnDestroy()
    44.     {
    45.         StartCoroutine(DisplayScreen());
    46.     }
    47.  
    48.     public void PlayerDying()
    49.     {
    50.         deathVFX.transform.parent = null; // deathVFX loses it's child relationship with player parent
    51.         deathVFX.Play();
    52.         audioSFX.audioSource.PlayOneShot(audioSFX.deathSFX, 1.5f);        
    53.         Destroy(ball);
    54.         Instantiate(loseScreen, playerUI); // instantiates loseScreen below UI game object
    55.     }
    56.  
    57.    public IEnumerator DisplayScreen() // IEnumerator used to give a delay to some action also called coroutine
    58.     {            
    59.         yield return new WaitForSeconds(delayToShowScreen); // gives a delay time
    60.         Debug.Log(loseScreen);
    61.         Instantiate(loseScreen, playerUI); // instantiates loseScreen below UI game object
    62.     }
    63.  
    64.     private void ReloadScene()
    65.     {      
    66.         sceneLoader.ReloadScene();
    67.     }
    68. }
    69.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,514
    Once you reach OnDestroy() your GameObject is toast, which means that the MonoBehaviors on it are also toast.

    Coroutines run in the context of a MonoBehavior, which has to be on a GameObject and operational to start.

    You can make a general purposes "CallAfterDelay" mechanism to do any arbitrary piece of code after a certain amount of time, regardless of where it was started from or the condition of your objects. This is the one I use:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CallAfterDelay : MonoBehaviour
    5. {
    6.     float delay;
    7.     System.Action action;
    8.    
    9.     public static CallAfterDelay Create( float delay, System.Action action)
    10.     {
    11.         CallAfterDelay cad = new GameObject("CallAfterDelay").AddComponent<CallAfterDelay>();
    12.         cad.delay = delay;
    13.         cad.action = action;
    14.         return cad;
    15.     }
    16.    
    17.     IEnumerator Start()
    18.     {
    19.         yield return new WaitForSeconds( delay);
    20.         action();
    21.         Destroy ( gameObject);
    22.     }
    23. }
    To use it you would do something like:

    Code (csharp):
    1. CallAfterDelay.Create( 2.0f, () => {
    2.   Debug.Log( "It is now two seconds later.");
    3. });
    That syntax with the => arrow and block is called an anonymous delegate or anonymous function and is just a block of arbitrary code that CallAfterDelay will call, after the delay has expired.