Search Unity

Coroutine isn't finished but SetActive executes

Discussion in 'Scripting' started by winterfive, Sep 14, 2018.

  1. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    Hello,

    I am taking an object (shotObject) and using a coroutine to loop through some colors/alphas to make it look like its disappearing. Once the alpha is 0, I want to setActive to false. When I test my code, the object disapears immediately but I can see my debug messages in the console showing that the color changes are happening. I have googled and read the unity docs and watched the unity video on this.

    Here's the code:
    Code (CSharp):
    1. private void CheckForEnemy()
    2.     {
    3.         if (_raycastManager.GetCurrentFoundObject() != null)
    4.         {
    5.             shotObject = _raycastManager.GetCurrentFoundObject().transform.root.gameObject;
    6.  
    7.             if (shotObject.tag == "Enemy")
    8.             {
    9.                 DestroyEnemy();
    10.             }
    11.         }      
    12.     }
    13.  
    14.  
    15.     private void DestroyEnemy()
    16.     {
    17.         shotObject.GetComponent<NavMeshAgent>().speed = 0;
    18.         shotObject.GetComponent<DroneActions>().IsShooting = false;
    19.         StartCoroutine(FadeEffect());
    20.     }
    21.  
    22.  
    23.     private IEnumerator FadeEffect()
    24.     {
    25.         Renderer[] components = shotObject.GetComponentsInChildren<Renderer>();
    26.  
    27.         foreach (Renderer r in components)
    28.         {
    29.             r.material.mainTexture = null;
    30.         }
    31.  
    32.         foreach (Color c in destructionColors)
    33.         {
    34.             foreach (Renderer r in components)
    35.             {
    36.                 r.material.color = c;
    37.                 Debug.Log("Fading out drone to color: " + c);
    38.             }
    39.  
    40.             yield return new WaitForSeconds(waitBetweenColors);
    41.         }
    42.  
    43.         yield return new WaitForSeconds(1f);
    44.         shotObject.SetActive(false);
    45.     }
    I don't want to place SetActive in my fadeEffect method (it shouldn't go there). But, from what I understand of the unity docs/video, this version should work. Help please, thanks!
     
    Last edited: Sep 14, 2018
  2. Tosatsu

    Tosatsu

    Joined:
    Sep 4, 2014
    Posts:
    14
    Try to add a boolean to check for coroutine entry and exit based on it's value of true/false, and also check if you're creating multiple Coroutines for the same object, that might have some weird effect. I still see it flowing properly, the logic doesn't appear off, but the code doesn't tell me on which monobehaviours they stay.
    If possible, try to put the FadeEffect under the fading Enemy so never more than one coroutine is created, and disable the collider on entry.
     
    winterfive likes this.
  3. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    Thanks for your reply! I made a flag as you suggested but the object still disapears before the color changes finish. Here's the updated code:
    Code (CSharp):
    1.  
    2. private void DestroyEnemy()
    3.     {
    4.         _hasFaded = false;
    5.         shotObject.GetComponent<NavMeshAgent>().speed = 0;
    6.         shotObject.GetComponent<DroneActions>().IsShooting = false;
    7.         StartCoroutine(FadeEffect());
    8.         if (_hasFaded)
    9.         {
    10.             shotObject.SetActive(false);
    11.         }    
    12.     }
    13.  
    14.  
    15. private IEnumerator FadeEffect()
    16.     {
    17.         Renderer[] components = shotObject.GetComponentsInChildren<Renderer>();
    18.  
    19.         foreach (Renderer r in components)
    20.         {
    21.             r.material.mainTexture = null;
    22.         }
    23.  
    24.         foreach (Color c in destructionColors)
    25.         {
    26.             foreach (Renderer r in components)
    27.             {
    28.                 r.material.color = c;
    29.                 Debug.Log("Fading out drone to color: " + c);
    30.             }
    31.  
    32.             yield return new WaitForSeconds(waitBetweenColors);
    33.         }
    34.  
    35.         _hasFaded = true;
    36.     }
    I declared the bool _hasFaded at the top of the class.
     
    Last edited: Sep 14, 2018
  4. Tosatsu

    Tosatsu

    Joined:
    Sep 4, 2014
    Posts:
    14
    Does Debug.Log("Fading out drone to color: " + c); actually appear in the logs, and does it respect the timing set by yield return new WaitForSeconds(waitBetweenColors); ?
    Set waitBetweenColors to a large value ~3-4-5 seconds, see what happens.
    Also I will guess there should be no chance that no renderers or colors are present.
    Try adding a yield return null at the end of the IEnumerator. I'm not sure but I think it causes an issue if your return options in the enumeration are all under conditions with no default :)
     
    winterfive likes this.
  5. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    The last console message is:
    Fading out drone to color: RGBA(0.000, 0.000, 0.000, 0.000)
    UnityEngine.Debug:Log(Object)
    <FadeEffect>c__Iterator0:MoveNext() (at Assets/Scripts/GameManager.cs:110)
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    I get a message for each color change prior as well and each pops up at the right time (roughly 1 1/2 seconds each). I changed the waitForColors to 5 and the messages popped up slowly. With the new WaitForSeconds at the end, the object still disappears immediately.

    Updated code:
    Code (CSharp):
    1. private void DestroyEnemy()
    2.     {
    3.         _hasFaded = false;
    4.         shotObject.GetComponent<NavMeshAgent>().speed = 0;
    5.         shotObject.GetComponent<DroneActions>().IsShooting = false;
    6.         StartCoroutine(FadeEffect());
    7.         if (_hasFaded)
    8.         {
    9.             shotObject.SetActive(false);
    10.         }      
    11.     }
    12.  
    13.  
    14.     private IEnumerator FadeEffect()
    15.     {
    16.         Renderer[] components = shotObject.GetComponentsInChildren<Renderer>();
    17.  
    18.         foreach (Renderer r in components)
    19.         {
    20.             r.material.mainTexture = null;
    21.         }
    22.  
    23.         foreach (Color c in destructionColors)
    24.         {
    25.             foreach (Renderer r in components)
    26.             {
    27.                 r.material.color = c;
    28.                 Debug.Log("Fading out drone to color: " + c);
    29.             }
    30.  
    31.             yield return new WaitForSeconds(waitBetweenColors);
    32.         }
    33.  
    34.         _hasFaded = true;
    35.         yield return new WaitForSeconds(waitBeforeDestroy);
    36.     }
     
  6. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    I figured out the issue. In Update() in another class, I was checking the navMesh agent speed as one requirement for returning the object to the pool (if speed >= 0). When the object was shot by the player, I changed the speed to 0 and thus causing it to be returned to the pool (set active to false) immediately. I changed my code a bit and now you can see the object fade out as I wanted.
     
    Tosatsu likes this.
  7. Tosatsu

    Tosatsu

    Joined:
    Sep 4, 2014
    Posts:
    14
    Talk about getting trolled by your own code. Happens to everyone. Try to keep your actions to objects standardized, such as set active in a single place, so you can check what calls that function! ;)
    Happy coding.
     
    winterfive and Munchy2007 like this.