How to make OnTriggerStay ColorLerp start all over again OnTrigger?

Hi,

My code is not working properly. I want my Player to change color overtime when it is located in a Zone. It does work when I am in the first Zone, but when i go to another Zone, which has the same tag as the first one, It continues the Lerp where it ended in the first Zone.

So basically I am asking, if there is any way to reset to the StartColor everytime I am in a Zone? Or do you have any other sollutions?

Thanks a lot guys!

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class ChangeColorOnTrigger : MonoBehaviour
 {
      public float speedIn = 1.0f;
      public float speedOut = 1.0f;
    public Color startColor;
    public Color endColor;
    float startTime;


 
     // Start is called before the first frame update
     void Start()
     {
         startTime = Time.time;
     }
 
  void OnTriggerStay(Collider col){
      if (col.gameObject.tag == "zone1"){
            float t = (Time.time - startTime) * speedIn;
            GetComponent<Renderer>().material.SetColor("_BaseColor",  Color.Lerp(startColor, endColor, t));
        }
  }

void OnTriggerExit(Collider col){
      if (col.gameObject.tag == "zone1"){
            float t = (Time.time - startTime) * speedOut;
            GetComponent<Renderer>().material.SetColor("_BaseColor",  Color.Lerp(endColor, startColor, t));
        }
     }
  }

Some key points for your code:


  • Try not to use GetComponent every frame, it is not as performant. Store references to it once.
  • You don’t really need to assign startTime. Time.time itself is good enough for most purposes, it contains the seconds since Unity starts.
  • CompareTag is safer as it checks string value issues on runtime instead of quietly failing.
  • The [SerializeField] attribute is more appropriate than making something public, at least if you want it to be inspector-settable only.
  • Values which never change can use const for extra clarity (and extra clues to the compiler, where needed).
  • OnTriggerStay runs all the time in the trigger collider. OnTriggerEnter however is more appropriate if you only want something to trigger once.
  • Outsource the actual lerping into another function called from Update, this guarantees it will continue running as needed.

Here’s one way to do it. Note however there’s also full libraries for tweening, like LeanTween, which might help you.


using UnityEngine;

public class ChangeColorOnTrigger : MonoBehaviour
{
    [SerializeField] Color endColor;
    Color startColor;

    const float speed = 1f;
    const string colliderTag = "zone1";

    Color? targetColor = null;
    Material material = null;
    float lerpAmount = 0f;
       
    void Awake()
    {
        material = GetComponent<Renderer>().material;
        startColor = material.color;
    }

    void Update()
    {
        FollowTargetColor();
    }

    void FollowTargetColor()
    {
        if (targetColor != null)
        {
            lerpAmount = Mathf.Clamp(lerpAmount + Time.deltaTime * speed, 0f, 1f);
            material.color = Color.Lerp(material.color, (Color) targetColor, lerpAmount);
            if (lerpAmount >= 1f) { targetColor = null; }
        }
    }

    void OnTriggerEnter(Collider collider)
    {
       if (collider.CompareTag(colliderTag))
       {
           SetNewTargetColor(endColor);
        }
    }

    void OnTriggerExit(Collider collider)
    {
        if (collider.CompareTag(colliderTag))
        {
           SetNewTargetColor(startColor);
        }
    }

   void SetNewTargetColor(Color color)
   {
       lerpAmount = 0f;
       targetColor = color;
   }

}

It is working for me like this. Thanks a lot @JPhilipp!

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class ChangeColorOnTrigger : MonoBehaviour
  {
      [SerializeField] Color endColor;
      Color startColor;
  
      const float speed = 1f;
      const string colliderTag = "zone1";
  
      Color? targetColor1 = null;
      Color? targetColor2 = null;
      Material material = null;
      float lerpAmount = 0f;
         
      void Awake()
      {
          material = GetComponent<Renderer>().material;
          startColor = material.color;
      }
  
      void Update()
      {
          FollowTargetColor();
      }
  
      void FollowTargetColor()
      {
          if (targetColor1 != null)
          {
              lerpAmount = Mathf.Clamp(lerpAmount + Time.deltaTime * speed, 0f, 1f);
              GetComponent<Renderer>().material.SetColor("_BaseColor",  Color.Lerp((Color) targetColor1, (Color) targetColor2, lerpAmount));
              if (lerpAmount >= 1f) { targetColor1 = null; }
              if (lerpAmount >= 1f) { targetColor2 = null; }
          }
      }
  
      void OnTriggerEnter(Collider collider)
      {
         if (collider.CompareTag(colliderTag))
         {
             SetNewTargetColor1(startColor);
             SetNewTargetColor2(endColor);
          }
      }
  
      void OnTriggerExit(Collider collider)
      {
          if (collider.CompareTag(colliderTag))
          {
             SetNewTargetColor1(endColor);
             SetNewTargetColor2(startColor);
          }
      }
  
     void SetNewTargetColor1(Color color1)
     {
         lerpAmount = 0f;
         targetColor1 = color1;
     }
     void SetNewTargetColor2(Color color2)
     {
         lerpAmount = 0f;
         targetColor2 = color2;
     }
  
  }