Change Background images smoothly in Unity2d - c#

I have 12 background images which are a little bit different from each other and I need to have smooth transitions while changing, it shouldn't be a distraction for a player.
my code:
IEnumerator changeBackground(){
while (true){
x = Random.Range(0,12);
background.sprite = Sprites[x];
yield return new WaitForSeconds(5f);
}
}

As mentioned you probably won't come around having two overlayed images and fade.
To make it easy you could use a forth and back fading of a single image while the other stays always opaque and do e.g.
public Image background;
public Image backgroundFade;
public float fadeDuration = 1f;
private readonly Color _fadeStartColor = new Color(1, 1, 1, 0);
IEnumerator changeBackground()
{
while (true)
{
x = Random.Range(0,12);
backgroundFade.sprite = Sprites[x];
backgroundFade.color = _fadeStartColor;
backgroundFade.gameObject.SetActive(true);
for(var timePassed = 0f; timePassed < fadeDuration; timePassed += Time.deltaTime)
{
backgroundFade.color = Color.Lerp(fadeStartColor, Color.white, timePassed / fadeDuration);
yield return null;
}
background.sprite = Sprites[x];
backgroundFade.gameObject.SetActive(false);
yield return new WaitForSeconds(5f);
}
}
Now you simply need to create an image as child of your background and make it stretch to the full size of the background. Then make it initially inactive and reference it into backgroundFade

Related

Fading an Image UI with pressing a key in Unity

I want to fade an image if I press down key "A", I found a code here, in stackoverflow and tried to overwrite it to work as I want, but it still doesn't fade out my image.
public float FadeRate;
private Image image;
private float targetAlpha;
void Start()
{
if (Input.GetKeyDown(KeyCode.A))
{
image = GetComponent<Image>();
Material instantiatedMaterial = Instantiate<Material>(image.material);
image.material = instantiatedMaterial;
targetAlpha = image.color.a;
StartCoroutine(FadeIn());
}
}
IEnumerator FadeIn()
{
targetAlpha = 1.0f;
Color curColor = image.color;
while (Mathf.Abs(curColor.a - targetAlpha) > 0.0001f)
{
Debug.Log(image.material.color.a);
curColor.a = Mathf.Lerp(curColor.a, targetAlpha, FadeRate * Time.deltaTime);
image.color = curColor;
yield return null;
}
}
So first of all you have your check which button is pressed in the wrong method. Your start method should look like this:
void Start()
{
image = GetComponent<Image>();
Material instantiatedMaterial = Instantiate<Material>(image.material);
image.material = instantiatedMaterial;
targetAlpha = image.color.a;
}
Your if statement has to go into your update method. The start method only runs once after the object is initalized. Your update method runs every frame. You want to check every frame if the A key was pressed.
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
StartCoroutine(FadeIn());
}
}
Your coroutine actually looks fine. It is doing what it should do: Fade your image in and not out. You can easily see that by looking at its name. It is called FadeIn. Your image is fading in because its targetAlpha is set to 1f. This has to be changed to zero. I also renamed your method accordingly.
IEnumerator FadeOut()
{
targetAlpha = 0f;
Color curColor = image.color;
while (Mathf.Abs(curColor.a - targetAlpha) > 0.0001f)
{
Debug.Log(image.material.color.a);
curColor.a = Mathf.Lerp(curColor.a, targetAlpha, FadeRate * Time.deltaTime);
image.color = curColor;
yield return null;
}
}
Just as an addition to Daniel M's answer.
You can actually make Start itself to be a Coroutine in which case you actually could do
private IEnumerator Start()
{
var image = GetComponent<Image>();
var startAlpha = image.color.a;
var targetAlpha = 1.0f;
var curColor = image.color;
yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.A));
while (!Mathf.Abs(curColor.a - targetAlpha) > 0.0001f)
{
Debug.Log(image.material.color.a);
curColor.a = Mathf.Lerp(curColor.a, targetAlpha, FadeRate * Time.deltaTime);
image.color = curColor;
yield return null;
}
// In order to end with clean values
curColor.a = targetAlpha;
image.color = curColor;
}
Note though that your Lerp will always start pretty fast and get slower and slower and probably never really reach the target alpha.
If you want to rather fade in a fixed time you could use
[SerializeField] private float duration = 2f;
and then
for(var factor = 0f; factor < 1; factor += Time.deltaTime / duration)
{
// Optionally add ease-in and -out
factor = Mathf.SmoothStep(0, 1, factor);
curColor.a = Mathf.Lerp(startAlpha, targetAlpha, factor);
image.color = curColor;
yield return null;
}
// In order to end with clean values
curColor.a = targetAlpha;
image.color = curColor;
And then if you want total control of the blend curve you could also use an
[SerializeField] private AnimationCurve _fadeCurve;
configure it according to your needs in the Inspector and do
for(var factor = 0f; factor < 1; factor += Time.deltaTime / duration)
{
factor = _fadeCurve.Evaluate(factor);
curColor.a = Mathf.Lerp(startAlpha, targetAlpha, factor);
image.color = curColor;
yield return null;
}
// In order to end with clean values
curColor.a = targetAlpha;
image.color = curColor;

Unity Lerping the volume of an AudioSource to 0.01 works but lerping it back to 1.0 causes the source to break

I unfortunately hit a roadblock with this audio fading function I've made. It takes in a source, duration and a new clip. It is supposed to fade out the initial clip, replace the clip and lerp the volume back to 1.
public static IEnumerator FadeSwitchAudio(AudioSource audioSource, float duration, int clip)
{
float firstTimer = 0;
float secondTimer = 0;
float start = audioSource.volume;
// Fade audio out, works as intended
while (firstTimer < duration)
{
firstTimer += Time.deltaTime;
audioSource.volume = Mathf.Lerp(start, 0.01f, firstTimer / duration);
yield return null;
}
audioSource.clip = GameObject.FindWithTag("AudioManager").GetComponent<AudioManager>().clips[clip];
// Fade audio back in, volume jumps immediately to 1 and audiosource stops having output
yield return new WaitForSeconds(0.1f);
while (secondTimer < duration)
{
secondTimer += Time.deltaTime;
audioSource.volume = Mathf.Lerp(start, 1.0f, secondTimer / duration);
yield return null;
}
}
I have tried a lot of different timer functions, however, it seems that increasing the volume of an audiosource always breaks it. Is there a sure way to slowly increase the audio of a source without the source completely losing output? Here is a gif of the current behaviour in the inspector. Please excuse the low resolution but you can see the behaviour.
Unity Audio Lerping Issue
Thank you for your time!
Two issues here:
Only changing the AudioSource.clip doesn't do anything.
Assigning clip with a new audio clip does not instantly change the clip that is being played
You additionally need to start playing that new clip using AudioSource.Play.
Also as a new start for the second loop you do not want to use the original AudioSource.volume you have stored at the top of the Corouinte but rather the current one after fading out.
So just a little bit redactored I would use e.g.
private const float FADED_OUT_VOLUME = 0.01f;
public static IEnumerator FadeSwitchAudio(AudioSource audioSource, float duration, int clip)
{
var originalVolume = audioSource.volume;
// I prefer using for loops over while to eliminate the danger of infinite loops
// and the need for "external" variables
// I personally also find this better to read and maintain
for(var timePassed = 0f; timePassed < duration; timePassed += Time.deltaTime)
{
audioSource.volume = Mathf.Lerp(originalVolume, FADED_OUT_VOLUME, timePassed / duration);
yield return null;
}
// To be sure to end with clean values
audioSource.volume = FADED_OUT_VOLUME;
// If there is only one instance of `AudioManager` in your scene this is more efficient
// in general you should fetch that AudioManager reference only ONCE and re-use it
audioSource.clip = FindObjectOfType<AudioManager>().clips[clip];
//audioSource.clip = GameObject.FindWithTag("AudioManager").GetComponent<AudioManager>().clips[clip];
yield return new WaitForSeconds(0.1f);
// Actually start playing the new clip
audioSource.Play();
for(var timePassed = 0f; timePassed < duration; timePassed += Time.deltaTime)
{
audioSource.volume = Mathf.Lerp(FADED_OUT_VOLUME, originalVolume, timePassed / duration);
yield return null;
}
audioSource.volume = 1f;
}

How to fade in and out [duplicate]

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.

How to make invisible game object with transparent/diffuse with alpha 0 to visible alpha 255 over time

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 :)

Animate buttons (slide left, slide right, slide down) in unity3d v4.6

While Instantiating the buttons and adding them to the scene, I need to perform some kind of animations, so they get added to the scene with a slide down animation (or slide left or slide right).
My code so far:
for (int i = 0; i < 4; i++) {
// Instantiate 4 buttons
Transform clone = (Transform)Instantiate (suggestionBtn,
new Vector3 (4, y, 0), Quaternion.identity);
// make instance the child of the canvas
clone.SetParent(gameObject.transform, false);
clone.transform.rotation = transform.localRotation;
y -= 70;
}
I am not sure whether I need to make animation files and attach them to each button I need to animate or use some engine like LeanTween or is it just few lines of code that will ensure slide down/ slide left/ slide right animations?
You can use iTween to do this:
static float y0;
static float FadeInOutTime = 1.0f;
//Called in Awake()
y0 = GameObject.Find("button_home").transform.position.y;
public static IEnumerator AnimateIn ()
{
int i = 0;
foreach (var item in ToolbarButtons) {
var pos = item.transform.position;
iTween.MoveTo(item, new Vector3(pos.x, y0 + 6, pos.z), FadeInOutTime);
yield return new WaitForSeconds (i * 0.02f);
i++;
}
yield return null;
}

Categories