Hi there! I’ve been encountering some issues in my color changing script that should change the color of the entire level every once in a while and make the background a slightly darker shade of that random color.The issue that I’m facing is that, once my spawner script creates a new level part as the game is endless, the previous parts that were created do not change colors.Only the last created level part gets it’s color changed and the background.How may I go about changing this so it could identify the previous created level parts and make them have the same color?
Here is the script that I’m currently using :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Level_ColorChanger : MonoBehaviour
{
//How fast do we change
public float ChangeTime = 2f;
//How long do we wait before changing again
public List<SpriteRenderer> _spriteRenderers;
float r;
float g;
float b;
private Image background;
public float WaitTime = 3f;
private WaitForSeconds _waitTime;
void Start()
{
//Make a new List
_spriteRenderers = new List<SpriteRenderer>();
//Find our renderers
var sprites = GameObject.FindGameObjectsWithTag("ColoredPart_Level");
background = GameObject.FindGameObjectWithTag("ColoredPart_Background").GetComponent<Image>();
for (var i = 0; i < sprites.Length; i++)
{
//See if it has a renderer on it
var renderer = sprites[i].GetComponent<SpriteRenderer>();
//Add it to the list if it does
if(renderer)
{
_spriteRenderers.Add(renderer);
}
}
_waitTime = new WaitForSeconds(WaitTime);
StartCoroutine(ChangeColor());
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Player"))
{
StartCoroutine(ChangeColor());
}
}
private IEnumerator ChangeColor()
{
var count = _spriteRenderers.Count;
if (count <= 0)
{
Debug.LogError("No sprite renderes found");
yield break;
}
//Loop the Coroutine rather that start a new one each time it finishes
while (true)
{
//Assuming they all start at the same colour, we will just get the colour of the first item
var startColour = _spriteRenderers[0].color;
//Get a random color to change to
int color_index = Random.Range(0, 2);
if (color_index == 0)
{
r = 1f;
g = Random.Range(0, 0.9f);
b = Random.Range(0, 0.9f);
}
if (color_index == 1)
{
r = Random.Range(0, 0.9f);
g = 1f;
b = Random.Range(0, 0.9f);
}
if (color_index == 2)
{
r = Random.Range(0, 0.9f);
g = Random.Range(0, 0.9f);
b = 1f;
}
Color newColor = new Color(r, g, b);
Color bgColor = new Color(r - 0.6f, g - 0.6f, b - 0.6f);
var t = 0f;
while (t <= 1)
{
var lerpedColour = Color.Lerp(startColour, newColor, t);
background.color = Color.Lerp(startColour, bgColor, t);
for (var i = 0; i < count; i++)
{
_spriteRenderers[i].color = lerpedColour;
}
//Update our t according to how much time has passed
t += Time.deltaTime / ChangeTime;
yield return null;
}
yield return _waitTime;
}
}
}
Feel free to use it in your own projects if this is the intended behaviour that you need!
I would really appreciate some help as I’m still at the beggining and would like some explanations of what’s happening if any modifications are provided.I’ve been stuck for at least 2 hours trying to find a solution to what I need my script to be adapted into and didn’t succeed.
No, this is the entire script, just forgot to delete the old comments because this script has been repurposed a few times.
The onTriggerEnter is also there because I was about to do something with that and make it be able to switch colors once on trigger enter for levels and make it do what I have written in the post for the endless mode of the game.Currently I have delayed that idea to finish the endless way of working for this script and then come back to that and adapt the script a bit accordingly.It should not be taken into consideration as it does nothing currently.
Maybe start printing out (with Debug.Log()) the names of the objects that it is changing and the colors it is changing them to, like immediately before the actual change of color is executed?
Alright, I’m back after doing that, pretty sure I’ve done it in a proper way haha
Here’s the code just in case
private IEnumerator ChangeColor()
{
var count = _spriteRenderers.Count;
if (count <= 0)
{
Debug.LogError("No sprite renderes found");
yield break;
}
//Loop the Coroutine rather that start a new one each time it finishes
while (true)
{
//Assuming they all start at the same colour, we will just get the colour of the first item
var startColour = _spriteRenderers[0].color;
//Get a random color to change to
int color_index = Random.Range(0, 2);
if (color_index == 0)
{
r = 1f;
g = Random.Range(0, 0.9f);
b = Random.Range(0, 0.9f);
}
if (color_index == 1)
{
r = Random.Range(0, 0.9f);
g = 1f;
b = Random.Range(0, 0.9f);
}
if (color_index == 2)
{
r = Random.Range(0, 0.9f);
g = Random.Range(0, 0.9f);
b = 1f;
}
Color newColor = new Color(r, g, b);
Color bgColor = new Color(r - 0.6f, g - 0.6f, b - 0.6f);
var t = 0f;
while (t <= 1)
{
var lerpedColour = Color.Lerp(startColour, newColor, t);
background.color = Color.Lerp(startColour, bgColor, t);
for (var i = 0; i < count; i++)
{
_spriteRenderers[i].color = lerpedColour;
}
//Update our t according to how much time has passed
t += Time.deltaTime / ChangeTime;
yield return null;
}
if(t >= 1)
{
for (var i = 0; i < count; i++)
{
Debug.Log(_spriteRenderers[i]);
}
}
yield return _waitTime;
}
}
And it seems that every time it prints 19 sprite renderers,and one level part has 18 sprite renderers that should change color + the background so that’s 19, I guess it doesn’t keep the previous level parts in the list that should change them all?
Would identifying the renderers continously fix this?Even though it would be a pretty costly way of doing things.
//Placing this in the Update instead of it being in the Start Method
for (var i = 0; i < sprites.Length; i++)
{
//See if it has a renderer on it
var renderer = sprites[i].GetComponent<SpriteRenderer>();
//Add it to the list if it does
if(renderer)
{
_spriteRenderers.Add(renderer);
}
}
This is what I tried.As I couldn’t get the reference to the sprites, I decided that temporarily I’ll get it inside the Update method with the check so it can find the objects.Here is the code :
void Update()
{
var sprites = GameObject.FindGameObjectsWithTag("ColoredPart_Level");
for (var i = 0; i < sprites.Length; i++)
{
//See if it has a renderer on it
var renderer = sprites[i].GetComponent<SpriteRenderer>();
//Add it to the list if it does
if (renderer)
{
_spriteRenderers.Add(renderer);
}
}
}
This apparently makes it so it can’t find any spriterenderers at all, I will look a bit into it and get back to you if I can’t figure it out on my own.
Edit : I have turned the sprites var into a GameObject[ ] and made it public so I can access it anywhere.
Alright, I’m back after trying some things.Currently I’m running the script like this and found out the following things :
(code here)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Level_ColorChanger : MonoBehaviour
{
//How fast do we change
public float ChangeTime = 2f;
//How long do we wait before changing again
public List<SpriteRenderer> _spriteRenderers;
float r;
float g;
float b;
private Image background;
public float WaitTime = 3f;
private WaitForSeconds _waitTime;
public GameObject[] sprites;
void Start()
{
//Make a new List
_spriteRenderers = new List<SpriteRenderer>();
//Find our renderers
background = GameObject.FindGameObjectWithTag("ColoredPart_Background").GetComponent<Image>();
sprites = GameObject.FindGameObjectsWithTag("ColoredPart_Level");
_waitTime = new WaitForSeconds(WaitTime);
StartCoroutine(ChangeColor());
}
void Update()
{
for (var i = 0; i < sprites.Length; i++)
{
//See if it has a renderer on it
var renderer = sprites[i].GetComponent<SpriteRenderer>();
//Add it to the list if it does
if (renderer)
{
_spriteRenderers.Add(renderer);
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Player"))
{
StartCoroutine(ChangeColor());
}
}
private IEnumerator ChangeColor()
{
var count = _spriteRenderers.Count;
if (count <= 0)
{
Debug.LogError("No sprite renderes found");
yield break;
}
//Loop the Coroutine rather that start a new one each time it finishes
while (true)
{
//Assuming they all start at the same colour, we will just get the colour of the first item
var startColour = _spriteRenderers[0].color;
//Get a random color to change to
int color_index = Random.Range(0, 2);
if (color_index == 0)
{
r = 1f;
g = Random.Range(0, 0.9f);
b = Random.Range(0, 0.9f);
}
if (color_index == 1)
{
r = Random.Range(0, 0.9f);
g = 1f;
b = Random.Range(0, 0.9f);
}
if (color_index == 2)
{
r = Random.Range(0, 0.9f);
g = Random.Range(0, 0.9f);
b = 1f;
}
Color newColor = new Color(r, g, b);
Color bgColor = new Color(r - 0.6f, g - 0.6f, b - 0.6f);
var t = 0f;
while (t <= 1)
{
var lerpedColour = Color.Lerp(startColour, newColor, t);
background.color = Color.Lerp(startColour, bgColor, t);
for (var i = 0; i < count; i++)
{
_spriteRenderers[i].color = lerpedColour;
}
//Update our t according to how much time has passed
t += Time.deltaTime / ChangeTime;
yield return null;
}
if(t >= 1)
{
for (var i = 0; i < count; i++)
{
Debug.Log(_spriteRenderers[i]);
}
}
yield return _waitTime;
}
}
}
And it seems that other than not being able to identify the renderers, the sprites array stays stuck at 14, and that’s the number of sprites that are inside the scene when it starts.I’ve waited for a few level parts to instantiate, and it doesn’t update nor get their renderers.This is a weird issue.Why can’t it get the renderers of the sprites if it’s identifying it the same way? Am I missing something here?
Edit once again so I don’t keep posting stuff : I didn’t realise that I left the sprites array in the start method and moved it into Update, now the number of gameobjects that should be in that array updates properly, but the renderers still can’t get pulled.
Interesting… try perhaps searching for them by FindObjectsOfType(), even though I know that will find ALL sprite renderers, probably not what you want… something’s funny here because what you’re doing with the tag should work (even though it might be problematic performance-wise). This is just investigation obviously.
Try this also: run the game until you’re confident there should be renderers it’s not finding, then pause the game and go dig through the hierarchy, see if the tags are correct, etc… it sounds like something isn’t quite set up the way your code is expecting it.
Don’t worry, we’ll track it down. If necessary make a dupe scene that is drastically simplified and see what’s going on. Something is happening we’re not considering yet…
Alright, I have tried placing a Debug.Log inside the for statement that I put in the Update Method, and it displays all of the game objects that should get in there.So they get inside the array properly and finds the spriteRenderers but I think that they are not written in the list for some weird reason, because when it gets inside the coroutine it stops, the _spriteRenderers count is still 0 and it kind of makes the Debug.Log sound invalid.
The issue isn’t tag-wise or something placed wrong in the Hierarchy for sure, the script worked properly in it’s initial state and it identified sprites and their renderers properly.
I have also tried putting the var count = _spriteRenderers.count and it’s if statement inside the while loop and it still doesn’t get it updated properly, something is breaking somewhere in between but I can’t realise where that’s happening.
Not sure what the state of your script is now but looking at the latest above, you are creating the list in Start(), then every frame you are adding ALL the renderers to the list… Update() runs every frame!
This can’t possibly be intended.
Let’s try this:
make the list in Start() (as you are)
when you create a level piece, call a function in this colorizer and add it to the list
when you destroy a level piece, call another function in this colorizer script and remove it from the list
don’t use a coroutine:
Instead of a coroutine, have a “desiredColor,” a “previousColor” and a fraction.
When you choose to do a new color:
set that fraction to 0
set previousColor to desiredColor
set desiredColor to the newly-chosen color
In Update, whenever that fraction is less than 1.0, iterate all SpriteRenderers and do a Color.Lerp() from previousColor to desiredColor, using the fraction.
Also increase the fraction by an amount. If you want it to change in 1/2 a second, count up by 2 * Time.deltaTime, for instance.
When that fraction gets greater than or equal to 1.0, stop the lerping and set the sprite renderers all to be desiredColor.
Then your Update() just sits there waiting for fraction to return to zero.
Thanks for the suggestion! I will try this later as I’m not home and come back with an update! I wasn’t about to add the renderers to the list via Update, it was just for the debugging, I’ll try to implement this when I will have access to my pc and come back with the code.
Hi there! I’m back after a few days.Had some issues that kept me from fixing this issue and trying your suggestions.I’ll try to implement this right now, but I have a question.What’s the advantage of using the fraction and previousColor , desiredColor instead of a Coroutine?
Also, how would I go about saving the color of each level part?As the previous ones will have a color and the newly created ones will be white as that’s the default color, the color gets changed after it’s instantiated.Shouldn’t I need a way to save the color values of each level part and then lerp from those to the desired color using a for or something?