- Home /
Material Colour Change, Loop
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class WhiteSheep : MonoBehaviour { public GameObject[] sheep; public GameObject[] trees;
void Start()
{
int colour = getRandomInt(0, 2);
if (colour == 1)
{
Renderer rend = GetComponent<Renderer>();
//so we can access the colour
rend.material.shader = Shader.Find("_Color");
rend.material.SetColor("_Color", Color.red);
rend.material.shader = Shader.Find("Specular");
rend.material.SetColor("_SpecColor", Color.red);
//Find the Specular shader and change its Color to red
}
else if (colour == 0)
{
Renderer rend = GetComponent<Renderer>();
//so we can access the colour
rend.material.shader = Shader.Find("_Color");
rend.material.SetColor("_Color", Color.blue);
rend.material.shader = Shader.Find("Specular");
rend.material.SetColor("_SpecColor", Color.blue);
}
}
private int getRandomInt(int start, int end)
{
float fRandom = Random.Range(start, end);
int iRandom = Mathf.FloorToInt(fRandom);
return iRandom;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.CompareTag ("Player"))
{
foreach (GameObject tree in trees)
{
Renderer rend = tree.GetComponent<Renderer>();
rend.material.shader = Shader.Find("_Color");
rend.material.SetColor("_Color", Color.magenta);
rend.material.shader = Shader.Find("Specular");
rend.material.SetColor("_SpecColor", Color.magenta);
}
}
}
}
I want to make the colour change to be repeated by using a loop, but when I add a loop into the void Start, it happens too quick that I can't observe it happening. Is there any way slowing down the loop in Unity?
Answer by UnityCoach · Sep 26, 2018 at 07:54 AM
3 solutions :
Make Start a Coroutine
Make Start call InvokeRepeating
Use Update to increment a timer, using Time.deltaTime
Some suggestions :
Keep a reference to the Renderer, don't use GetComponent each time
Shader.Find returns a Shader to pass a Material constructor, not a property, not sure what you intend to do with
Shader.Find("_Color");
Accessing a Renderer's material returns a copy, thus creating a new instance. It's better if you can replace the material with a reference you already have.
Random.Range already has an int version, no need to floor the result.
You can go with something in the lines of :
public class MaterialSwitch : MonoBehaviour
{
Material[] materials = new Material[2];
Renderer _renderer;
void Awake ()
{
_renderer = GetComponent<Renderer>();
}
IEnumerator Start ()
{
WaitForSeconds wait = new WaitForSeconds(1f);
while (true)
{
yield return wait;
_renderer.material = materials[Random.Range(0,2)];
}
}
}
Wait a moment, you can make Start a coroutine and it will be called by Unity like a regular Start?! That's a gamechanger, is it written somewhere?
You can refer it here: https://docs.unity3d.com/$$anonymous$$anual/Coroutines.html
I can't see anything about this in your link, sorry
Yes, it's here, and there, and some other messages can also be coroutines, like OnTriggerEnter for example.
Thanks a lot, that's an amazing piece of information, I can't believe I lived without it (no sarcasm here)
Answer by Casiell · Sep 26, 2018 at 07:57 AM
The code in Start will be executed during a single frame, that's why you can't see anything.
What you want to do is use a Coroutine. Create a coroutine, put your loop inside and in each iteration of your loop write a 'yield return'. Note that you can't coroutines like normal methods, you have to use StartCoroutine instead.
Example code:
private void Start()
{
StartCoroutine(ChangeColors());
}
private IEnumerator ChangeColors()
{
foreach(Color c in colors)
{
tree.color = c;
yield return new WaitForSeconds(1);
}
}
Your answer
Follow this Question
Related Questions
GL.LINES cannot switch colors 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
OverlapSphere for parallel arrays 1 Answer