Search Unity

Can't run my coroutine OnDestroy()?

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

  1. brunoenvia

    brunoenvia

    Joined:
    Aug 5, 2019
    Posts:
    52
    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:
    5,055
    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.
     
unityunity