- Home /
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));
}
}
}
Have yout tried the "OnTriggerEnter" $$anonymous$$ethod ?
Answer by cublai · Mar 15, 2020 at 07:48 AM
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;
}
}
@cublai Replace GetComponent<Renderer>().material.SetColor(...)
with material.SetColor(...)
for better performance -- it is suggested to not call GetComponent every frame, but to cache it into a reference (which is already assigned in Awake()
).
Answer by JPhilipp · Mar 14, 2020 at 05:40 PM
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;
}
}
Could you please show me how to reset the lerp so it starts from the startColor everytime it hits the Trigger?
Your answer
Follow this Question
Related Questions
Controlling duration of Color.Lerp in seconds 2 Answers
Color lerp once? 2 Answers
Distribute terrain in zones 3 Answers
Time.deltaTime making color lerp appear fast, but won't reach 1 1 Answer
Smooth gradient between colours? 1 Answer