Hello!
I’m making a little practice project. There are blocks on the screen and I want them to constantly change colors.
I have written this (which is a mush of this: Smooth continuous color change over the game? - Unity Engine - Unity Discussions and this: https://codepen.io/Codepixl/pen/ogWWaK ):
but his code stops after a single transition.
void Update()
{
colorChange();
}
private void colorChange()
{
if (timeLeft <= Time.deltaTime)
{
if (r >= 0f && b == 0f)
{
r--;
g++;
}
if (g >= 0f && r == 0f)
{
g--;
b++;
}
if (b >= 0f && g == 0f)
{
r++;
b--;
}
// transition complete
// assign the target color
GetComponent<SpriteRenderer>().color = targetColor;
// start a new transition
targetColor = new Color(r, g, b, 1f);
timeLeft = 1.0f;
}
else
{
// transition in progress
// calculate interpolated color
GetComponent<SpriteRenderer>().color = Color.Lerp(GetComponent<SpriteRenderer>().color, targetColor, Time.deltaTime / timeLeft);
// update the timer
timeLeft -= Time.deltaTime;
}
}
Any ideas how to rewrite this code so it works? I’m new to coding real-time code.
Thanks for reading this, and have a nice day!
reppeti:
g == 0f
First, never test floating point for equality. This might work as long as g was really set to zero, but it is not a good habit to get into.
Second, this indicates to me you are thinking 0 to 255:
reppeti:
r++;
But you are using this constructor:
new Color(r, g, b, 1f);
which accepts numbers from 0.0f to 1.0f (such as the alpha term above, which is optional and defaults to 1.0f anyway)
Are you looking for new Color32()
perhaps?
Also, you can use Color.Lerp() to smoothly change between any two arbitrary colors.
Smoothing movement between any two particular values:
https://discussions.unity.com/t/812925/5
You have currentQuantity and desiredQuantity.
only set desiredQuantity
the code always moves currentQuantity towards desiredQuantity
read currentQuantity for the smoothed value
Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.
The code: https://gist.github.com/kurtdekker/fb3c33ec6911a1d9bfcb23e9f62adac4
2 Likes
Kurt-Dekker:
First, never test floating point for equality. This might work as long as g was really set to zero, but it is not a good habit to get into.
Second, this indicates to me you are thinking 0 to 255:
But you are using this constructor:
new Color(r, g, b, 1f);
which accepts numbers from 0.0f to 1.0f (such as the alpha term above, which is optional and defaults to 1.0f anyway)
Are you looking for new Color32()
perhaps?
Also, you can use Color.Lerp() to smoothly change between any two arbitrary colors.
Smoothing movement between any two particular values:
https://discussions.unity.com/t/812925/5
You have currentQuantity and desiredQuantity.
only set desiredQuantity
the code always moves currentQuantity towards desiredQuantity
read currentQuantity for the smoothed value
Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.
The code: https://gist.github.com/kurtdekker/fb3c33ec6911a1d9bfcb23e9f62adac4
Thanks! I tweaked the code a bit to make sure no float shenanigans happen and now it works.
void Update()
{
colorChange();
Debug.Log((int)r);
Debug.Log(g);
Debug.Log(b);
}
private void colorChange()
{
if (timeLeft <= Time.deltaTime)
{
if ((int)Math.Round(r) >= 0 && (int)Math.Round(b) == 0)
{
r -=0.1f;
g += 0.1f;
}
if ((int)Math.Round(g) >= 0 && (int)Math.Round(r) == 0)
{
g -= 0.1f;
b += 0.1f;
}
if ((int)Math.Round(b) >= 0 && (int)Math.Round(g) == 0)
{
r += 0.1f;
b -= 0.1f;
}
// transition complete
// assign the target color
GetComponent<SpriteRenderer>().color = targetColor;
// start a new transition
targetColor = new Color(r, g, b, 1f);
timeLeft = 1.0f;
}
else
{
// transition in progress
// calculate interpolated color
GetComponent<SpriteRenderer>().color = Color.Lerp(GetComponent<SpriteRenderer>().color, targetColor, Time.deltaTime / timeLeft);
// update the timer
timeLeft -= Time.deltaTime;
}
}
You’re still overcomplicating the problem. I’m not sure why you’re doing the whole Math.Round rigamaorale in the first place but that part of the if statement is going to evalute to true anytime that color is less than half of total brightness, which doesn’t seem like something you want. And changing the color value by 0.1 each time it changes is just not a particularly smooth transition.
I think you would benefit from the Gradient class . You can make a public Gradient member:
public Gradient colorGradient;
…and edit it in the Inspector to look like a rainbow in the pattern you want to animate through, starting and ending with the same color. And then you can just do something like this to animate using that gradient:
public Gradient colorGradient;
public float gradientDuration = 10f; //seconds
private float currentTime = 0f;
void Update() {
currentTime += Time.deltaTime;
if (currentTime > gradientDuration) currentTime = 0f;
GetComponent<SpriteRenderer>().color = colorGradient.Evaluate(currentTime / gradientDuration);
}
1 Like
StarManta:
You’re still overcomplicating the problem. I’m not sure why you’re doing the whole Math.Round rigamaorale in the first place but that part of the if statement is going to evalute to true anytime that color is less than half of total brightness, which doesn’t seem like something you want. And changing the color value by 0.1 each time it changes is just not a particularly smooth transition.
I think you would benefit from the Gradient class . You can make a public Gradient member:
public Gradient colorGradient;
…and edit it in the Inspector to look like a rainbow in the pattern you want to animate through, starting and ending with the same color. And then you can just do something like this to animate using that gradient:
public Gradient colorGradient;
public float gradientDuration = 10f; //seconds
private float currentTime = 0f;
void Update() {
currentTime += Time.deltaTime;
if (currentTime > gradientDuration) currentTime = 0f;
GetComponent<SpriteRenderer>().color = colorGradient.Evaluate(currentTime / gradientDuration);
}
My code also preserves color difference between blocks. Also it work smoothly because of the Lerp.
Edit: How to inspect a gradient? It’s in thje code? By serializing it?
Edit: Yeah Serializing seems to work. How could I preserve the color difference with this?
Here is my full code currently:
public class CookieBlock : MonoBehaviour
{
Color originalColor;
float r = 1f;
float b = 0f;
float g = 0f;
float timeLeft;
Color targetColor;
public Gradient colorGradient;
public float gradientDuration = 10f; //seconds
private float currentTime = 0f;
void Start()
{
originalColor = gameObject.GetComponent<SpriteRenderer>().color;
r = originalColor.r;
g = originalColor.g;
}
//int state = 0;
void Update()
{
colorChange();
}
private void colorChange()
{
currentTime += Time.deltaTime;
if (currentTime > gradientDuration) currentTime = 0f;
GetComponent<SpriteRenderer>().color = colorGradient.Evaluate(currentTime / gradientDuration);
/*
if (timeLeft <= Time.deltaTime)
{
if ((int)Math.Round(r) >= 0 && (int)Math.Round(b) == 0)
{
r -=0.1f;
g += 0.1f;
}
if ((int)Math.Round(g) >= 0 && (int)Math.Round(r) == 0)
{
g -= 0.1f;
b += 0.1f;
}
if ((int)Math.Round(b) >= 0 && (int)Math.Round(g) == 0)
{
r += 0.1f;
b -= 0.1f;
}
// transition complete
// assign the target color
GetComponent<SpriteRenderer>().color = targetColor;
// start a new transition
targetColor = new Color(r, g, b, 1f);
timeLeft = 0.3f;
}
else
{
// transition in progress
// calculate interpolated color
GetComponent<SpriteRenderer>().color = Color.Lerp(GetComponent<SpriteRenderer>().color, targetColor, Time.deltaTime / timeLeft);
// update the timer
timeLeft -= Time.deltaTime;
}
*/
}
I don’t know what you mean by this.
public class ColorChange : MonoBehaviour
{
private Camera cam;
private float duration = 60f;
private void Start()
{
cam = GetComponent<Camera>();
}
private void Update()
{
float hue = (Time.time * duration) % 360f;
Color newColor = Color.HSVToRGB(hue / 360f, 0.3f, 1f);
cam.backgroundColor = newColor;
}
}
Let’s not over complicate things… XD
1 Like
Closing this thread as a resolution has been found.