I wrote this little Unity3D class to fade an array of UI.Image in or out by reducing or increasing the alpha value of their color property. Then I wanted to use it for an array of materials on meshrenderers but realized that materials and UI.Image, though they both have a color property which can be changed, are totally different classes and you access their color properties differently so I cannot use this class for them both.
I tried making a list of just the colors to be changed, but in unity a Color is a struct and cannot be passed by reference.
Do you have any idea how to make this class generic so it can change the color property on several different classes? I sort of wrote myself into a corner here, I'd rather not just copy the class and change it for meshrenderer.material, that would be ugly
public class FadeThingInOut : MonoBehaviour
{
//public Setting fields
public Image[] ThingsToFade;
public bool Visible = true;
public float FadeTime = 1f;
//private fields
Color[] InColour;
Color[] OutColor;
void Start()
{
if (Visible)
{
SetColours(ref InColour, ref OutColor,0f);
}
else
{
SetColours(ref OutColor,ref InColour,1f);
}
}
void SetColours(ref Color[] one,ref Color[] two,float other)
{
one = new Color[ThingsToFade.Length];
two = new Color[ThingsToFade.Length];
for (int i = 0; i < ThingsToFade.Length; i++)
{
one[i] = ThingsToFade[i].color;
two[i] = Tools.colorfromalpha(one[i], other);
}
}
public void Fade(bool inout)
{
if (inout && !Visible)
{
StartCoroutine(FadeLerp(OutColor,InColour,inout));
}
else if (!inout && Visible)
{
StartCoroutine(FadeLerp(InColour, OutColor, inout));
}
}
IEnumerator FadeLerp(Color[] from, Color[] to,bool endstate)
{
float nowtime = 0f;
while (nowtime < FadeTime)
{
nowtime += Time.deltaTime;
float ratio = nowtime / FadeTime;
for (int i = 0; i < ThingsToFade.Length; i++)
{
ThingsToFade[i].color = Color.Lerp(from[i], to[i], ratio);
yield return null;
}
}
for (int i = 0; i < ThingsToFade.Length; i++)
{
ThingsToFade[i].color = to[i];
}
Visible = endstate;
}
Heres what I ended up doing.
I keep an array of the components and then cast them to one of three types that I am dealing with. There is a series of if statements to deal with the different classes differntly.
I'm still interested in a more elegant solution that may use some aspects of .net or C# that I'm not familiar with though
public class FadeThingInOut : MonoBehaviour
{
//public Setting fields
public Component[] ThingsToFade;
public bool Visible = true;
public float FadeTime = 1f;
public float Max = 1f;
//private fields
Color[] InColour;
Color[] OutColor;
void Start()
{
if (Visible)
{
SetColours(ref InColour, ref OutColor,0f);
}
else
{
SetColours(ref OutColor, ref InColour, Max);
}
}
void SetColours(ref Color[] one,ref Color[] two,float other)
{
one = new Color[ThingsToFade.Length];
two = new Color[ThingsToFade.Length];
for (int i = 0; i < ThingsToFade.Length; i++)
{
one[i] = GetColour(i);
two[i] = Tools.colorfromalpha(one[i], other);
}
}
public void Fade(bool inout)
{
if (inout && !Visible)
{
StartCoroutine(FadeLerp(OutColor,InColour,inout));
}
else if (!inout && Visible)
{
StartCoroutine(FadeLerp(InColour, OutColor, inout));
}
}
Color GetColour(int index)
{
if(ThingsToFade[index].GetType() == typeof(MeshRenderer))
{
return (ThingsToFade[index] as MeshRenderer ).material.color;
}
else if (ThingsToFade[index].GetType() == typeof(Image))
{
return (ThingsToFade[index] as Image).color;
}
else if (ThingsToFade[index].GetType() == typeof(RawImage))
{
return (ThingsToFade[index] as RawImage).material.color;
}
return Color.black;
}
void SetColour(int index,Color col)
{
if (ThingsToFade[index].GetType() == typeof(MeshRenderer))
{
(ThingsToFade[index] as MeshRenderer).material.color = col;
return;
}
else if (ThingsToFade[index].GetType() == typeof(Image))
{
(ThingsToFade[index] as Image).color = col;
return;
}
else if (ThingsToFade[index].GetType() == typeof(RawImage))
{
(ThingsToFade[index] as RawImage).material.color = col;
return;
}
}
IEnumerator FadeLerp(Color[] from, Color[] to,bool endstate)
{
float nowtime = 0f;
while (nowtime < FadeTime)
{
nowtime += Time.deltaTime;
float ratio = nowtime / FadeTime;
for (int i = 0; i < ThingsToFade.Length; i++)
{
SetColour(i, Color.Lerp(from[i], to[i], ratio));
yield return null;
}
}
for (int i = 0; i < ThingsToFade.Length; i++)
{
SetColour(i, to[i]);
}
Visible = endstate;
}
}
This isn't super ideal but you can do it this way.
public interface ISetColor
{
public Color color { get; set; }
}
public class ImageSetColor : MonoBehaviour, ISetColor
{
public Image m_Image
public Color color { get {return m_Image.color;} set { m_Image.color = value}
}
public class MaterialSetColor : MonoBehaviour, ISetColor
{
public Material m_Material
public Color color { get {return m_Material.color;} set { m_Material.color = value}
}
Then instead of an Image array you can do an array of public MonoBehaviour[] ThingsToFade
then anytime you use ThingsToFade
you need to cast it to an ISetColor.
Then any component you want to be able to set colors with will need to create a class that inherits from MonoBehaviour and implements the ISetColor interface
This isn't the easiest solution to use in Unity but it should work
You should not write a class. You should write an extension method. Because structs are immutable though, you cannot change their value, so you should write a static function that has as an argument a reference to color, by using the "ref" keyword. Using structs as mutable objects is not recommended most of the time, but it's the best option here.
I wrote this little Unity3D class to fade an array of UI.Image in or out by reducing or increasing the alpha value of their color property.
I dont see why to overcomplicate everything.
Edit: This will fade by adjusting the alpha directly, using floats instead of color swapping. Faster, cheaper, shorter.
IEnumerator FadeLerp(float _from, float _to, bool endstate)
{
float nowtime = 0f;
while (nowtime < FadeTime)
{
nowtime += Time.deltaTime;
float ratio = nowtime / FadeTime;
for (int i = 0; i < ThingsToFade.Length; i++)
{
Color _color = ThingsToFade[i].color;
_color.a = Mathf.Lerp(_from, _to, ratio);
ThingsToFade[i].color = _color;
yield return null;
}
}
for (int i = 0; i < ThingsToFade.Length; i++)
{
ThingsToFade[i].renderer.enabled = endstate;
}
}
use color.lerp function. it will fade the color nicely, and if you know how to use the lerp, with a counter and with an array, there should not be a problem :) if tomorrow you are still stucked i'll write the lerping function for you, but keep trying :) It will be a sweet experience if you do it on your own :D
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.