I'm fairly new to coding, I'm still trying to develop that logic of thinking to help me create the solutions I'm wanting for games. Currently, I'm in Unity trying to create a 2D GameObject that's a wall hiding a secret door. I want that GameObject to fade out (about 90%) when the player GameObject triggers it, revealing the space behind and the hidden door.
So far, I've managed to figure out how to render the "secret wall" GO inactive on the trigger, so it disappears, but this doesn't produce the visual that I'm going for. As I said, I'm still working on developing that coder's way of thinking, so while I've done a lot of research to solve this problem, many of the results I don't readily understand.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SecretDoor1 : MonoBehaviour {
void OnTriggerEnter2D (Collider2D SecretDoorTrig) {
if (SecretDoorTrig.gameObject.tag == "Player") {
GetComponent<SpriteRenderer> ().enabled = false;
}
else {
GetComponent<SpriteRenderer> ().enabled = true;
}
}
void OnTriggerExit2D (Collider2D SecretDoorTrig) {
if (SecretDoorTrig.gameObject.tag == "Player") {
GetComponent<SpriteRenderer> ().enabled = true;
}
else {
GetComponent<SpriteRenderer> ().enabled = false;
}
}
}
Fading a Sprite is almost the-same as moving GameObject over time except that you modify its alpha instead of it's position.
The three most important stuff about fading an Object are Time.deltaTime, Mathf.Lerp/Color.Lerp and coroutine. You need to understand how these work together.
Start coroutine, use Time.deltaTime to increment a variable. That variable is used to use to determine how much that function has ran. In a for/while loop, use that variable that is incremented every-frame and the duration you want the fade to happen to generate the alpha with the help of the Mathf.Lerp function. Create new color with that alpha and and assign it to the Sprite.
This is done every frame until that variable that is incremented with Time.deltaTime reaches the duration you want to the fade to happen within.
Here is a simple SpriteRenderer fade function:
public SpriteRenderer spriteToFade;
IEnumerator fadeOut(SpriteRenderer MyRenderer, float duration)
{
float counter = 0;
//Get current color
Color spriteColor = MyRenderer.material.color;
while (counter < duration)
{
counter += Time.deltaTime;
//Fade from 1 to 0
float alpha = Mathf.Lerp(1, 0, counter / duration);
Debug.Log(alpha);
//Change alpha only
MyRenderer.color = new Color(spriteColor.r, spriteColor.g, spriteColor.b, alpha);
//Wait for a frame
yield return null;
}
}
If you want it to fade in, change Mathf.Lerp(1, 0, counter / duration); to Mathf.Lerp(0, 1, counter / duration); which will make the alpha go from 0 to 1 over-time instead of 1 to 0.
From the example above, writing a fade-out and fade-in functions only requires a way to tell the function to change the alpha from 1 to 0 or from 0 to 1. You can make the function use a boolean or enum variable to determine which type of fade to perform. Of-course, you can separate the fade-in/fade-out functions but it's good to have it in one function.
Here is the extended version of that function that supports fade-in and fade-out. It also supports almost all GameObjects like MeshRenderer(3D), SpriteRenderer(2D), Image, RawImage....You can extend it to support more components that's missing.
IEnumerator fadeInAndOut(GameObject objectToFade, bool fadeIn, float duration)
{
float counter = 0f;
//Set Values depending on if fadeIn or fadeOut
float a, b;
if (fadeIn)
{
a = 0;
b = 1;
}
else
{
a = 1;
b = 0;
}
int mode = 0;
Color currentColor = Color.clear;
SpriteRenderer tempSPRenderer = objectToFade.GetComponent<SpriteRenderer>();
Image tempImage = objectToFade.GetComponent<Image>();
RawImage tempRawImage = objectToFade.GetComponent<RawImage>();
MeshRenderer tempRenderer = objectToFade.GetComponent<MeshRenderer>();
Text tempText = objectToFade.GetComponent<Text>();
//Check if this is a Sprite
if (tempSPRenderer != null)
{
currentColor = tempSPRenderer.color;
mode = 0;
}
//Check if Image
else if (tempImage != null)
{
currentColor = tempImage.color;
mode = 1;
}
//Check if RawImage
else if (tempRawImage != null)
{
currentColor = tempRawImage.color;
mode = 2;
}
//Check if Text
else if (tempText != null)
{
currentColor = tempText.color;
mode = 3;
}
//Check if 3D Object
else if (tempRenderer != null)
{
currentColor = tempRenderer.material.color;
mode = 4;
//ENABLE FADE Mode on the material if not done already
tempRenderer.material.SetFloat("_Mode", 2);
tempRenderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
tempRenderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
tempRenderer.material.SetInt("_ZWrite", 0);
tempRenderer.material.DisableKeyword("_ALPHATEST_ON");
tempRenderer.material.EnableKeyword("_ALPHABLEND_ON");
tempRenderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
tempRenderer.material.renderQueue = 3000;
}
else
{
yield break;
}
while (counter < duration)
{
counter += Time.deltaTime;
float alpha = Mathf.Lerp(a, b, counter / duration);
switch (mode)
{
case 0:
tempSPRenderer.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 1:
tempImage.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 2:
tempRawImage.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 3:
tempText.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 4:
tempRenderer.material.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
}
yield return null;
}
}
Usage:
GameObject to fade:
public GameObject SpriteRend;
Fade-out in 3 seconds
StartCoroutine(fadeInAndOut(SpriteRend, false, 3f));
Fade-in in 3 seconds
StartCoroutine(fadeInAndOut(SpriteRend, true, 3f));
The way I have accomplished this has been change the alpha on the sprite color.
Color(R,G,B,A). A is the alpha.
SpriteRenderer.color = new Color(1f,1f,1f,1f) is opaque.
SpriteRenderer.color = new Color(1f,1f,1f,.5f) is about 50%
transparent.
SpriteRenderer.color = new Color(1f,1f,1f,0f) is about
100% transparent, sprite cannot be seen.
Related
How to make a sprite start to fade in and 1 second later when the opacity is 50% then its turning instantly to 100% and then 0.2 seconds later its within 0.5 seconds the opacity going to 100% to 0% and its repeat itself every 1 second?
I think this is a really hard question but I hope somebody will help my fix my problem.
-Thanks!
I'm not sure if it's the best solution but I have some idea how to realize it.
So we have Time.deltaTime valuable. It's the interval in seconds from the last frame to the current onetime to draw (Unity Documentation). So we can use it to count seconds. The other way to count secounds are Coroutines but it's more complicated in my opinion so I will use the first method.
So we have some Sprite we need to change.
public Sprite ourSprite;
Also (as DiplomacyNotWar proposed) we would use a simple state machine. We will use integer to store current state. And we need some timer to use it when we wait 0.2 seconds and when we wait 1 second before repeat:
public int state = 0;
public float timer = 0;
In Start() I find the SpriteRenderer component and set opacity to zero (to test work of the script).
void Start()
{
ourSprite = this.GetComponent<SpriteRenderer>();
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, 0);
}
And in Update() we realize out state machine. We use switch to control states. So we write simple code for each state and have this switch as a result:
void Update()
{
switch (state) {
case 0:
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, ourSprite.color.a + Time.deltaTime * 0.5f);
if (ourSprite.color.a >= 0.5f) {
state = 1;
}
break;
case 1:
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, 1f);
state = 2;
break;
case 2:
timer += Time.deltaTime;
if (timer >= 0.2f) {
timer = 0; //reseting timer
state = 3;
}
break;
case 3:
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, ourSprite.color.a - Time.deltaTime * 2f);
if (ourSprite.color.a <= 0) {
state = 4;
}
break;
case 4:
timer += Time.deltaTime;
if (timer >= 1f) {
timer = 0;
state = 0;
}
break;
}
}
The full code is here. I tested it on Unity 2021.3.5f1 and everything works fine. Don't forget to place this script on sprite object on your Scene and everything seems to work.
using UnityEngine;
using UnityEngine.UI;
public class spriteChange : MonoBehaviour
{
private SpriteRenderer ourSprite;
private int state = 0;
private float timer = 0;
// Start is called before the first frame update
void Start()
{
ourSprite = this.GetComponent<SpriteRenderer>();
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, 0); //setting sprite opacity to 0 in the beggining of scene
}
// Update is called once per frame
void Update()
{
switch (state) {
case 0:
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, ourSprite.color.a + Time.deltaTime * 0.5f);
if (ourSprite.color.a >= 0.5f) {
state = 1;
}
break;
case 1:
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, 1f);
state = 2;
break;
case 2:
timer += Time.deltaTime;
if (timer >= 0.2f) {
timer = 0; //reseting timer
state = 3;
}
break;
case 3:
ourSprite.color = new Color(ourSprite.color.r, ourSprite.color.g, ourSprite.color.b, ourSprite.color.a - Time.deltaTime * 2f);
if (ourSprite.color.a <= 0) {
state = 4;
}
break;
case 4:
timer += Time.deltaTime;
if (timer >= 1f) {
timer = 0;
state = 0;
}
break;
}
}
}
In most cases, coroutines will be fine for a such task.
(I wrote this code here, not in the IDE, so it can possibly contain some typos. But I think it will be enough to understand the principle and modify it according to your needs.)
// call this method when you need to begin the sequence
public void StartBlinking()
{
StartCoroutine(CoBlinking());
}
IEnumerator CoBlinking()
{
while(true) // to make this sequence repeat until we break it manually
{
// assume we have `_sprite` variable assigned
yield return StartCoroutine(CoChangeAlpha(_sprite, 0f, 0.5f, 1f));
SetSpriteAlpha(_sprite, 1f);
yield return new WaitForSeconds(0.2f);
yield return StartCoroutine(CoChangeAlpha(_sprite, 1f, 0f, 0.5f));
// add other delays or changes if you need
}
}
IEnumerator CoChageAlpha(Sprite sprite, float startAlpha, float endAlpha, float duration)
{
float elapsed = 0f;
while(elapsed < duration)
{
elapsed += Time.deltaTime;
float curAlpha = Mathf.Lerp(startAlpha, endAlpha, elapsed /
duration);
SetSpriteAlpha(sprite, curAlpha);
yield return null;
}
}
void SetSpriteAlpha(Sprite sprite, float newAlpha)
{
Color newColor = sprite.color;
newColor.a = newAlpha;
sprite.color = newColor;
}
I have a question please in my game when i write "LEFT" in a InputField and click on a UI Button the cube move "LEFT" and eat coins(the same for up, down , right) my problem is when i wrote this code below the player moved but not slowly more like disappear than appear in the position that declare it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public InputField mainInputField;
//public float speed;
public GameObject Player;
public Button Click_me;
public float smoothing = 1f;
public Transform TargetRight1;
public Transform TargetRight2;
public Transform TargetUP;
// Start is called before the first frame update
void Start()
{
}
public void SubmitName()
{
string[] lines = mainInputField.text.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
if (lines[i] == "UP")
{
// moveUP();
StartCoroutine(MyCoroutineUP(TargetUP));
}
else if (lines[i] == "DOWN")
{
//MoveDown();
}
else if (lines[i] == "LEFT")
{
//MoveLeft();
}
else if (lines[i] == "RIGHT")
{
StartCoroutine(MyCoroutineUP(TargetRight1));
}
}
// Click_me.interactable = false;
}
IEnumerator MyCoroutineUP(Transform target)
{
while (Vector3.Distance(Player.transform.position, target.position) > 0.05f)
{
Player.transform.position = Vector3.Lerp(Player.transform.position, target.position, smoothing * Time.deltaTime);
}
yield return null;
}
}
know if i put the yield return null; inside the while loop like this
while (Vector3.Distance(Player.transform.position, target.position) > 0.05f)
{
Player.transform.position = Vector3.Lerp(Player.transform.position, target.position, smoothing * Time.deltaTime);
yield return null;
}
the player move slowly and get the coins but if i have more than 2 ligne for example i wrote LEFT , UP the while loop won't work properly when i call the function in the first line. sorry for my English
You will get concurrent Coroutines.
It sounds like what you actually are asking is how to stack multiple commands and work them one by one. This gets a bit more complex but sounds like the perfect usecase for a Queue
private readonly Queue<Transform> _commands = new Queue<Transform>();
public void SubmitName()
{
var lines = mainInputField.text.Split('\n');
mainInputField.text = "";
foreach (var line in lines)
{
switch (line)
{
case "UP":
// adds a new item to the end of the Queue
_commands.Enqueue(TargetUp);
break;
case "DOWN":
_commands.Enqueue(TargetDown);
break;
case "LEFT":
_commands.Enqueue(TargetLeft);
break;
case "RIGHT":
_commands.Enqueue(TargetRight);
break;
}
}
StartCoroutine(WorkCommands());
}
private IEnumerator WorkCommands()
{
// block input
Click_me.interactable = false;
// run this routine until all commands are handled
while (_commands.Count > 0)
{
// returns the first element and at the same time removes it from the queue
var target = _commands.Dequeue();
// you can simply yield another IEnumerator
// this makes it execute and at the same time waits until it finishes
yield return MovementCoroutine(target);
}
// when done allow input again
Click_me.interactable = true;
}
To the lerping itself:
I wouldn't lerp like that. That starts the movement very quick and gets slower in the end but never really reaches the target position. If thats what you want leave it but I would rather recommend doing something like
private IEnumerator MovementCoroutine(Transform target)
{
var startPos = transform.position;
var targetPos = target.position;
var timePassed = 0f;
do
{
var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / smoothing);
transform.position = Vector3.Lerp(startPos, targetPos, lerpFactor);
timePassed += Time.deltaTime;
yield return null;
}
while(timePassed < smoothing);
// just to be sure there is no over or undershooting
// in the end set the correct target position
transform.position = targetPos;
}
In smoothing you would then instead set the time in seconds the lerping should take in total. In my opinion this gives you more control. The SmoothStep makes the movement still being eased in and out.
If you want you could additionally also take the current distance into account for always making the object move with more or less the same speed regardless how close or far the target position is by adding/changing
var distance = Vector3.Distance(startPos, targetPos);
var duration = smoothing * distance;
do
{
var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / duration);
...
}
while (timePassed < duration);
now in smoothing you would rather set the time in seconds the object should need to move 1 Unity unit.
I don't know your exact setup for the targets ofcourse but this is how it would look like with targets attached to the player (so they move along with it)
Ok Im trying to lerp through 3 states where each has a different ambient light color. One of the states needs to alpha lerp in the alpha of a different material.
I have everything set up accordingly yet when I trigger the transition (using space), I dont get a smooth lerp but instead rapid flickering and then it eventually gets to the final color.
EDITED code (still not fully there):
public Color[] skyColors = new Color[3];
// added this just to see the result also in the inspector
public Color currentAmbientcolor;
public enum WeatherType
{
ClearSky,
Clouds,
RainStorm
}
public WeatherType currentWeather;
// how long should lerping take
// I find that easier to configure than using
// speed - if you don't like it you can use timePassed += Tie.deltaTime * speed again
public float LerpDuration = 1.0f;
public Material rainMat;
public bool isLerpingWeather;
public bool isLerpingRain;
// You can store those already in the beginning
// makes it a bit better performance
private Color rainFaidedOut;
private Color rainFaidedIn;
private void Awake()
{
rainFaidedOut = new Color(rainMat.color.r, rainMat.color.g, rainMat.color.b, 0);
rainFaidedIn = new Color(rainMat.color.r, rainMat.color.g, rainMat.color.b, 1);
StartCoroutine(GetWeather());
}
void SetWeather(string weatherval)
{
print("VAL: " + weatherval);
if (weatherval.ToLower().Contains("cloud"))
{
currentWeather = WeatherType.Clouds;
}
else if (weatherval.ToLower().Contains("rain") || weatherval.ToLower().Contains("storm") || weatherval.ToLower().Contains("mist"))
{
currentWeather = WeatherType.RainStorm;
}
else
{
currentWeather = WeatherType.ClearSky;
}
//weather = WeatherType.ClearSky;
UpdateWeather();
}
void UpdateWeather()
{
//check for change
if (!isLerpingWeather)
{
if (currentWeather != WeatherType.RainStorm) rainMat.color = rainFaidedOut;
switch (currentWeather)
{
case WeatherType.RainStorm:
RenderSettings.ambientSkyColor = skyColors[2];
break;
case WeatherType.ClearSky:
RenderSettings.ambientSkyColor = skyColors[0];
break;
case WeatherType.Clouds:
RenderSettings.ambientSkyColor = skyColors[1];
break;
default:
break;
}
}
}
IEnumerator GetWeather()
{
//LA = [34.05, -118.24]
//https://openweathermap.org/weather-conditions
string url;
WWW www = new WWW(url);
yield return www;
if (www.error == null)
{
var N = JSON.Parse(www.text);
string weatherid = N["weather"][0]["description"];
print(weatherid);
SetWeather(weatherid);
}
else
{
Debug.Log("ERROR: " + www.error);
}
}
private IEnumerator CycleWeather()
{
if (isLerpingWeather) yield break;
isLerpingWeather = true;
// get target color
var currentIndex = (int)currentWeather;
var newIndex = (currentIndex + 1) % skyColors.Length;
var targetColor = skyColors[newIndex];
currentWeather = (WeatherType)newIndex;
// Here I just guessed you want that the rainMat is already
// set to invisible when the weather has changed
// except for RainStorm
if (currentWeather != WeatherType.RainStorm) rainMat.color = rainFaidedOut;
// get current color
var currentColor = RenderSettings.ambientSkyColor;
var timePassed = 0f;
do
{
RenderSettings.ambientSkyColor = Color.Lerp(currentColor, targetColor, timePassed / LerpDuration);
// added this just to see it in the inspector
currentAmbientcolor = RenderSettings.ambientSkyColor;
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < LerpDuration);
// just to be sure there is no over/under shooting set the target value in the end
RenderSettings.ambientSkyColor = targetColor;
// added this just to see it in the inspector
currentAmbientcolor = RenderSettings.ambientSkyColor;
isLerpingWeather = false;
// after the currentWeather has changed start the LerpingRain routine
// for the two cases where you want it
// since you already have set the RenderSettings.ambientSkyColor = targetColor;
// there is reason to do so every frame again
if (currentWeather != WeatherType.RainStorm) StartCoroutine(LerpingRain());
}
private IEnumerator LerpingRain()
{
// skip if already lerping rain to avoid parallel routines
if (isLerpingRain) yield break;
// also skip if currently lerping wheather to avoid parallel routines
if (isLerpingWeather) yield break;
// set flag to be sure no other routine will be running
isLerpingRain = true;
var timePassed = 0f;
do
{
rainMat.color = Color.Lerp(rainFaidedOut, rainFaidedIn, timePassed / LerpDuration);
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < LerpDuration);
rainMat.color = rainFaidedIn;
isLerpingRain = false;
}
// Now only used to get the input
private void Update()
{
currentAmbientcolor = RenderSettings.ambientSkyColor;
//UpdateWeather();
// You want GetKeyDown here to execute this only once instead of every frame!
if (Input.GetKey("space") && !isLerpingWeather)
{
print("changing weather");
// Interrupt current routines
StopAllCoroutines();
StartCoroutine(CycleWeather());
}
}
Is there something Im missing?
I recommend to use a Coroutine instead. It would make it way easier to controll than doing everything in Update:
I had to invent your used data types and values a bit but I think it should come close to what you are using:
public class LerpExample : MonoBehaviour
{
public Color[] skyColors = new Color[3];
// added this just to see the result also in the inspector
public Color currentAmbientcolor;
public enum WeatherType
{
ClearSky,
Clouds,
RainStorm
}
public WeatherType currentWeather;
// how long should lerping take
// I find that easier to configure than using
// speed - if you don't like it you can use timePassed += Tie.deltaTime * speed again
public float LerpDuration = 1.0f;
public Material rainMat;
public bool isLerpingWeather;
public bool isLerpingRain;
// You can store those already in the beginning
// makes it a bit better performance
private Color rainFaidedOut;
private Color rainFaidedIn;
private void Awake()
{
rainFaidedOut = new Color(rainMat.color.r, rainMat.color.g, rainMat.color.b, 0);
rainFaidedIn = new Color(rainMat.color.r, rainMat.color.g, rainMat.color.b, 1);
}
private IEnumerator CycleWeather()
{
if (isLerpingWeather) yield break;
isLerpingWeather = true;
// get target color
var currentIndex = (int)currentWeather;
var newIndex = (currentIndex + 1) % skyColors.Length;
var targetColor = skyColors[newIndex];
currentWeather = (WeatherType)newIndex;
// Here I just guessed you want that the rainMat is already
// set to invisible when the weather has changed
// except for RainStorm
if (currentWeather != WeatherType.RainStorm) rainMat.color = rainFaidedOut;
// get current color
var currentColor = RenderSettings.ambientSkyColor;
var timePassed = 0f;
do
{
RenderSettings.ambientSkyColor = Color.Lerp(currentColor, targetColor, timePassed / LerpDuration);
// added this just to see it in the inspector
currentAmbientcolor = RenderSettings.ambientSkyColor;
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < LerpDuration);
// just to be sure there is no over/under shooting set the target value in the end
RenderSettings.ambientSkyColor = targetColor;
// added this just to see it in the inspector
currentAmbientcolor = RenderSettings.ambientSkyColor;
isLerpingWeather = false;
// after the currentWeather has changed start the LerpingRain routine
// for the two cases where you want it
// since you already have set the RenderSettings.ambientSkyColor = targetColor;
// there is reason to do so every frame again
if (currentWeather != WeatherType.RainStorm) StartCoroutine(LerpingRain());
}
private IEnumerator LerpingRain()
{
// skip if already lerping rain to avoid parallel routines
if (isLerpingRain) yield break;
// also skip if currently lerping wheather to avoid parallel routines
if (isLerpingWeather) yield break;
// set flag to be sure no other routine will be running
isLerpingRain = true;
var timePassed = 0f;
do
{
rainMat.color = Color.Lerp(rainFaidedOut, rainFaidedIn, timePassed / LerpDuration);
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < LerpDuration);
rainMat.color = rainFaidedIn;
isLerpingRain = false;
}
// Now only used to get the input
private void Update()
{
// You want GetKeyDown here to execute this only once instead of every frame!
if (Input.GetKey("space") && !isLerpingWeather)
{
print("changing weather");
// Interrupt current routines
StopAllCoroutines();
StartCoroutine(CycleWeather());
}
}
}
The cube is for simulating the rain Material fade. The Sphere has a normal white material and is for visualizing the ambient color fade.
I'm not 100% sure if this behaves exactly like what you wanted to achieve but my goal was to show you how to use Coroutines instead of all those flags and checks inside the Update method.
I'm creating a script that allows objects to be faded considering an interval of time.
The script works very well, however when an object is faded, it is still very visible in the inspector AND in the build.
Could someone explain me why and how to make an object completely invisible?
(I know I can "enable" the object, but isn't it using more resources than fading? I don't know :( )
Here is the code if I've made any mistake (code inspired from a topic in unity's forum)
// Update is called once per frame
void Update ()
{
MyTime = Time.deltaTime;
AccumulatedTime += MyTime;
if (this.name == "Cube (1)")
{
Debug.Log(AccumulatedTime);
}
if (SwitchVisibility == 1)
{
if (AccumulatedTime >= Interval && AccumulatedTime<= 2*Interval || AccumulatedTime >= 3*Interval && AccumulatedTime<= 4*Interval)
{
StartCoroutine(FadeTo(0.0f, 1.0f));
SwitchVisibility = 0;
}
}
if (SwitchVisibility == 0)
{
if (AccumulatedTime >= 0 && AccumulatedTime <= Interval || AccumulatedTime >= 2*Interval && AccumulatedTime <= 3*Interval)
{
StartCoroutine(FadeTo(1.0f, 1.0f));
SwitchVisibility = 1;
}
}
if (AccumulatedTime >= Interval * 4.5f)
{
AccumulatedTime = 0;
}
}
IEnumerator FadeTo(float aValue, float aTime)
{
float alpha = MyRenderer.material.color.a;
for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / aTime)
{
OriginalColor.a = Mathf.Lerp(alpha, aValue, t);
Color newColor = OriginalColor;
MyRenderer.material.color = newColor;
yield return null;
}
}
Here is what objects look like:
Assuming your code is fine, the problem very likely is from your Material settings. This changed in Unity 5. To change the alpha of a Mesh Renderer, you must also change the Material's Rendering Mode from Opaque(default) to Fade.
Transparent Mode is also fine but will will not be completely transparent and will result to the problem in your question.
You can change the mode from script.
Property Name: _Mode
With Debug.Log(MyRenderer.material.GetFloat("_Mode"));, I got the follwing values:
0 = Opaque
1 = Cutout
2 = Fade
3 = Transparent
We can change the Rendering Mode to Fade with MyRenderer.material.SetFloat("_Mode",2);
There is a known problem when setting the Render Mode from script. You must also update all other properties as well to make the change take effect. Here is a complete way to change your Render Mode to Fade from script:
MyRenderer.material.SetFloat("_Mode", 2);
MyRenderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
MyRenderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
MyRenderer.material.SetInt("_ZWrite", 0);
MyRenderer.material.DisableKeyword("_ALPHATEST_ON");
MyRenderer.material.EnableKeyword("_ALPHABLEND_ON");
MyRenderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
MyRenderer.material.renderQueue = 3000;
Finally, if the this is working for you then your script is not good. You can use the script below to fade in and fade out a Mesh Renderer.
public MeshRenderer MyRenderer;
bool fading = false;
void Fade(bool fadeIn, float duration)
{
if (fading)
{
return;
}
fading = true;
changeModeToFade();
StartCoroutine(FadeTo(fadeIn, duration));
}
void changeModeToFade()
{
MyRenderer.material.SetFloat("_Mode", 2);
MyRenderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
MyRenderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
MyRenderer.material.SetInt("_ZWrite", 0);
MyRenderer.material.DisableKeyword("_ALPHATEST_ON");
MyRenderer.material.EnableKeyword("_ALPHABLEND_ON");
MyRenderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
MyRenderer.material.renderQueue = 3000;
}
IEnumerator FadeTo(bool fadeIn, float duration)
{
//MyRenderer.material.
float counter = 0f;
//Set Values depending on if fadeIn or fadeOut
float a, b;
if (fadeIn)
{
a = 0;
b = 1;
}
else
{
a = 1;
b = 0;
}
//Enable MyRenderer component
if (!MyRenderer.enabled)
MyRenderer.enabled = true;
//Get original Mesh Color
Color meshColor = MyRenderer.material.color;
//Do the actual fading
while (counter < duration)
{
counter += Time.deltaTime;
float alpha = Mathf.Lerp(a, b, counter / duration);
Debug.Log(alpha);
MyRenderer.material.color = new Color(meshColor.r, meshColor.g, meshColor.b, alpha);
yield return null;
}
if (!fadeIn)
{
//Disable Mesh Renderer
MyRenderer.enabled = false;
}
fading = false; //So that we can call this function next time
}
void Start()
{
//Fade(true, 3f); //Fade In
Fade(false, 3f);//Fade Out
}
Good day all.
I'm making a tower defense game in Unity3D and I'm trying to create a tower build animation.
So basically, for testing purposes, I have a primitive cube with a material with the transparent/diffuse legacy shader and I've set it's color's alpha to 0 as the tower should be completely invisible when created. It has a Tower script attached to it for the animation. I have another script which deals with the placement of the tower cube.
How do I make a tower completely visible with alpha of 255 of it's material's color when it's created over a certain amount of time?
So if the tower's build time is 5 seconds, the alpha should become from 0 to 255 in 5 seconds.
I've tried the following (Tower.cs):
public float buildTime = 10;
private MeshRenderer mr;;
private Color currentColor;
private bool built = false;
void Start() {
mr = GetComponent<MeshRenderer>()
currentColor = mr.material.color;
StartCorroutine(BuildAnimation());
}
IEnumerator BuildAnimation() {
float a = 0;
Color newColor = new Color(currentColor.r, currentColor.g, currentColor.b, a);
while (!built) {
mr.material.color = newColor;
if (a >= 255) {
built = true;
}
a+= 255 / buildTime;
yield return new WaitForSeconds(255 / buildTime);
}
}
Help will really be appreciated, thanks in advance!
[Tooltip("Time to fade in seconds")]
public float FadeTime;
private float _alpha = 0.0f;
private const float _startAlpha = 0f;
private const float _endAlpha = 1.0f;
IEnumerator Fade(MeshRenderer myMesh)
{
for (float t = 0f; t < FadeTime; t += Time.deltaTime)
{
float normalizedTime = t / FadeTime;
_alpha = Mathf.Lerp(_startAlpha, _endAlpha, normalizedTime);
yield return null;
}
_alpha = _endAlpha;
myMesh.material.color = new Color(myMesh.material.color.r,myMesh.material.color.g,myMesh.material.color.b,_alpha)
}
Then pass your Mesh through through the Fade().
Thanks #Martin Mazza Dawson for the answer. Although it wasn't working properly at first I got it working with a simple fix.
IEnumerator Fade(MeshRenderer myMesh)
{
for (float t = 0f; t < FadeTime; t += Time.deltaTime)
{
float normalizedTime = t / FadeTime;
_alpha = Mathf.Lerp(_startAlpha, _endAlpha, normalizedTime);
// The fix
myMesh.material.color = new Color (myMesh.material.color.r, myMesh.material.color.g, myMesh.material.color.b, _alpha);
yield return null;
}
//_alpha = _endAlpha;
//myMesh.material.color = new Color (myMesh.material.color.r, myMesh.material.color.g, myMesh.material.color.b, _alpha);
}
Love you :)