Search Unity

Lerp Color with Coroutine started in OnTriggerEnter?

Discussion in 'Scripting' started by outtoplay, Jul 23, 2014.

  1. outtoplay

    outtoplay

    Joined:
    Apr 29, 2009
    Posts:
    741
    This is killing me. I want to fade a color's alpha to '0' with a coroutine fired off in an OnTriggerEnter. The command works fine in Update(), but I can't seem to set up the coroutine correctly. Would really...really appreciate some help. I'd like to lose the Update(), and just use the OnTrigger Enter / Exit. Here's where I am:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Vanish : MonoBehaviour
    5. {
    6.     Color myColor;
    7.     Color vanishColor;
    8.  
    9.     float duration = 1;  // duration in seconds
    10.     float t = 0;         // lerp control variable
    11.  
    12.     void Start()
    13.     {
    14.         myColor = renderer.material.color;
    15.         vanishColor = new Color(myColor.r, myColor.g, myColor.b, 0f);
    16.     }
    17.        
    18.     void Update()
    19.     {
    20.         if (t < 1)
    21.         {
    22.             t += Time.deltaTime/duration;    // increment time every update:
    23.         }
    24.         // The line below works fine, but starts as soon as the scene starts.
    25.         //renderer.material.color = Color.Lerp(myColor, vanishColor, t);
    26.     }
    27.  
    28.     void OnTriggerEnter (Collider other)
    29.     {
    30.         if(other.gameObject.tag == "Light")
    31.         {
    32.             StartCoroutine("Fade");
    33.         }
    34.     }
    35.  
    36.     IEnumerator Fade()
    37.     {
    38.         renderer.material.color = Color.Lerp(myColor, vanishColor, t);
    39.         yield return null;
    40.     }
    41.  
    42. }
     
  2. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
  3. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Wrap your lerp logic in
    Code (csharp):
    1.  
    2. while (renderer.material.color.a < vanishColor.a)
    3.  
    or something similar. Your coroutine is running 1 call of lerp, yielding a frame, and then exiting.
     
  4. outtoplay

    outtoplay

    Joined:
    Apr 29, 2009
    Posts:
    741
    Thanks guys, I knew it was some sort of time related thing, as that's why it worked happily in Update(). The UnityPatterns page looks terrific, never saw it before. Seems like my trouble is in the grasp of the loop that needs to surround my logic. Will march back into the frey.
     
  5. outtoplay

    outtoplay

    Joined:
    Apr 29, 2009
    Posts:
    741
    Okay, I modified how I approached this and it basically works. If you attach this script to a cube (with its collider set to Trigger), and you have a sphere with a Kinematic Rigidbody attached (tagged 'Player"), you can press Play and simply drag the sphere into the Cube's trigger and the cube 'hides'. When you pull it back, the cube will reappear. But it's not perfect.

    1- I left a Debug.Log in each IEnumerator to display how the value is not capped at 1 or 0 as specified in the While Loop. (this might not be significant, but I thought it was odd).
    2- I was hoping to delay the IEnumerator Show(), by using a WaitForSeconds(), but it stalls the smooth alpha return to 1.
    3 - If I pull the sphere in and out quickly during the fade, I can cause the alpha fade to stick. Is there a way to prevent this?

    Thanks for the help, I'm almost there.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Vanish : MonoBehaviour
    5. {
    6.     float waitTime = 2f;
    7.  
    8.     void OnTriggerEnter(Collider other)
    9.     {
    10.         if(other.gameObject.tag == "Player")
    11.         {
    12.             StartCoroutine("Hide");
    13.         }
    14.     }
    15.     void OnTriggerExit(Collider other)
    16.     {
    17.         if(other.gameObject.tag == "Player")
    18.         {
    19.             StartCoroutine("Show");
    20.         }
    21.     }
    22.  
    23.     IEnumerator Hide()
    24.     {
    25.  
    26.         while (renderer.material.color.a >= 0)
    27.         {
    28.             renderer.material.color -= new Color(0,0,0,.05f);
    29.             Debug.Log(renderer.material.color.a.ToString());
    30.  
    31.             yield return null;
    32.         }
    33.     }
    34.  
    35.     IEnumerator Show()
    36.     {
    37.         while (renderer.material.color.a <= 1)
    38.         {
    39.             renderer.material.color += new Color(0,0,0,.05f);
    40.             Debug.Log(renderer.material.color.a.ToString());
    41.          
    42.             yield return null;
    43.         }
    44.     }
    45. }
    46.  
     
  6. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
    1. First of all, your animation currently is frame-based. That means it will run differently on different FPSs. If you want it to run FPS-independently, you should pick a colorchange-per-second speed and multiply that by Time.deltaTime. Also, you can prevent the alpha from going over 1/under 0 by using Mathf.Clamp(). Put your alpha, min and max in there.

    2. I don't understand... you want it to wait for a few seconds, but isn't stalling the same as waiting? What effect are you trying to achieve?

    3. That happens because both co-routines run simultanously and cancel out each other's effect. You can prevent that by using a bool such as "isFading" and check that either before starting the coroutine or inside the coroutine. You could either have Hide/Show wait until the isFading flag is cleared, or you could use StopAllCoroutines before starting a new one.
     
  7. outtoplay

    outtoplay

    Joined:
    Apr 29, 2009
    Posts:
    741
    Morning Der_r,
    Appreciate your time and thought in answering. Plenty to chew on there, I'll clean up the code and let the lesson seep into my rapidly deteriorating mind...lol Oh, as for #2 that was poorly worded. What I meant to say was, that how I was 'waiting' was clearly not done correctly. IT was as if I inserted the WaitForSeconds() into the fade loop, and it was waiting a second(or whatever the delay was set to), each time the fade up looped, so it looked like the fade up was in super slow motion. What I was looking for was to let player leave the trigger, pause a sec(or whatever), and then trigger the loop. That should be pretty simple, but it's likely if I clear up the other stuff it will become more clear where to stick the Wait...

    This a simple event/action, yet just odd enough to make me have to really think about clean execution. The original version just had the vis/invis occur without a fade, but I liked the fade. So I guess I get to earn it. thanks.