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;
}
Related
In the start :
void Start()
{
ControlPanel.KeyPressed += OnKeyPressed;
}
In the event OnKeyPressed :
private void OnKeyPressed(PressedKeyCode[] obj)
{
float tempY = 0;
float tempX = 0;
// stable forward
if (hMove.y > 0)
tempY = - Time.fixedDeltaTime;
else
if (hMove.y < 0)
tempY = Time.fixedDeltaTime;
// stable lurn
if (hMove.x > 0)
tempX = -Time.fixedDeltaTime;
else
if (hMove.x < 0)
tempX = Time.fixedDeltaTime;
foreach (var pressedKeyCode in obj)
{
switch (pressedKeyCode)
{
case PressedKeyCode.SpeedUpPressed:
EngineForce += 0.1f;
break;
case PressedKeyCode.SpeedDownPressed:
EngineForce -= 0.12f;
if (EngineForce < 0) EngineForce = 0;
break;
case PressedKeyCode.ForwardPressed:
if (IsOnGround) break;
tempY = Time.fixedDeltaTime;
break;
case PressedKeyCode.BackPressed:
if (IsOnGround) break;
tempY = -Time.fixedDeltaTime;
break;
case PressedKeyCode.LeftPressed:
if (IsOnGround) break;
tempX = -Time.fixedDeltaTime;
break;
case PressedKeyCode.RightPressed:
if (IsOnGround) break;
tempX = Time.fixedDeltaTime;
break;
case PressedKeyCode.TurnRightPressed:
{
if (IsOnGround) break;
var force = (turnForcePercent - Mathf.Abs(hMove.y)) * HelicopterModel.mass;
HelicopterModel.AddRelativeTorque(0f, force, 0);
}
break;
case PressedKeyCode.TurnLeftPressed:
{
if (IsOnGround) break;
var force = -(turnForcePercent - Mathf.Abs(hMove.y)) * HelicopterModel.mass;
HelicopterModel.AddRelativeTorque(0f, force, 0);
}
break;
case PressedKeyCode.BackToBase:
{
Vector3 direction = helicopterPlatform.transform.position - transform.position;
Quaternion toRotation = Quaternion.FromToRotation(transform.forward, direction);
transform.rotation = Quaternion.Lerp(transform.rotation, toRotation, lookAtSpeed * Time.time);
//transform.LookAt(helicopterPlatform.transform);
}
break;
}
}
hMove.x += tempX;
hMove.x = Mathf.Clamp(hMove.x, -1, 1);
hMove.y += tempY;
hMove.y = Mathf.Clamp(hMove.y, -1, 1);
}
I added the last part :
case PressedKeyCode.BackToBase:
{
Vector3 direction = helicopterPlatform.transform.position - transform.position;
Quaternion toRotation = Quaternion.FromToRotation(transform.forward, direction);
transform.rotation = Quaternion.Lerp(transform.rotation, toRotation, lookAtSpeed * Time.time);
//transform.LookAt(helicopterPlatform.transform);
}
break;
When I used LookAt it was working fine but the rotation was a bit too fast, This is how I used the LookAt:
transform.LookAt(helicopterPlatform.transform);
Then I decided to use the direction , toRotation and the Quaternion.Lerp but now when I press the key code B that's the key code for backtobase it's making the object(helicopter) to rotate and then rotate back the direction it was facing and I need to press many times on B to make it rotate facing the helicopterPlatform.
This is a link for the complete script a bit long so I'm not sure if to put it in my question so I uploaded it to pastebin.com : https://pastebin.com/YDfbVkH6
The t value of Lerp is not a speed value, rather it is the progress between point A and B
From the docs on Lerp:
t: Value used to interpolate between a and b.
This means that if you got the following code
Quaternion.Lerp(transform.rotation, toRotation, t);
when t = 0 the lerp will return whatever is stored in transform.rotation and when t = 1 it will return whatever is in toRotation, t = 0.5f would return whatever is right in between these values and so on for any value between 0 and 1.
Time.time is stated as the following from the docs:
The time at the beginning of this frame (Read Only). This is the time in seconds since the start of the game.
So what you are essentially doing right now is:
transform.rotation = Quaternion.Lerp(transform.rotation, toRotation, lookAtSpeed * time since the start of the game);
as you can see after the scene has run for a couple of seconds (depending on your lookAtSpeed) this value will quickly exceed 1, meaning it will always return toRotation.
What you are looking for is rather to slowly increment the t value from 0 to 1 using a coroutine, looking something like this, which will slowly increment from 0 to 1 based on your lookAtSpeed
internal IEnumerator LerpToPosition()
{
lookAtSpeed = 2f;
float t = 0f;
while (t < 1f)
{
t += lookAtSpeed * Time.deltaTime;
transform.rotation = Quaternion.Lerp(transform.rotation, toRotation, t);
yield return waitFrame;
}
}
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)
I'm developing a game kinda like Flappy Bird and Jetpack Joyride and I have gotten as far as adding in the coins to purchase new characters with. But, when a coin spawns in, it spawns farther to the right of where a wall spawns and doing this was an attempt to try and stop the coins from spawning behind a wall. But now the walls are spawning on top of the coins. How can I fix this?
Code for the column spawning:
if (!GameController.instance.gamePaused)
{
timeSinceLastSpawned += Time.deltaTime;
if (!GameController.instance.gameOver && timeSinceLastSpawned >= spawnRate)
{
timeSinceLastSpawned = 0f;
float spawnYPosition = Random.Range(columnMin, columnMax);
columns[currentColumn].transform.position = new Vector2(spawnXPosition, spawnYPosition);
currentColumn++;
if (currentColumn >= columnPoolSize)
currentColumn = 0;
} //if
} //if
Code for the coins spawning:
if(!GameController.instance.gamePaused)
{
if (!GameController.instance.gameOver)
{
timeSinceLastSpawned += Time.deltaTime;
if (timeSinceLastSpawned>=spawnRate)
{
int randCoin = Random.Range(0, 99);
int coinRand = coinRarity[randCoin];
switch(coinRand)
{
case 1:
timeSinceLastSpawned = 0f;
float goldSpawnYPosition = Random.Range(coinMin, coinMax);
goldCoins[goldCurrentColumn].transform.position = new Vector2(spawnXPosition, goldSpawnYPosition);
goldCurrentColumn++;
if (goldCurrentColumn >= goldPoolSize)
goldCurrentColumn = 0;
break;
case 2:
timeSinceLastSpawned = 0f;
float diamondSpawnYPosition = Random.Range(coinMin, coinMax);
diamondCoins[diamondCurrentColumn].transform.position = new Vector2(spawnXPosition, diamondSpawnYPosition);
diamondCurrentColumn++;
if (diamondCurrentColumn >= diamondPoolSize)
diamondCurrentColumn = 0;
break;
case 3:
timeSinceLastSpawned = 0f;
float rubySpawnYPosition = Random.Range(coinMin, coinMax);
rubyCoins[rubyCurrentColumn].transform.position = new Vector2(spawnXPosition, rubySpawnYPosition);
rubyCurrentColumn++;
if (rubyCurrentColumn >= rubyPoolSize)
rubyCurrentColumn = 0;
break;
case 4:
timeSinceLastSpawned = 0f;
float emeraldSpawnYPosition = Random.Range(coinMin, coinMax);
emeraldCoins[emeraldCurrentColumn].transform.position = new Vector2(spawnXPosition, emeraldSpawnYPosition);
emeraldCurrentColumn++;
if (emeraldCurrentColumn >= emeraldPoolSize)
emeraldCurrentColumn = 0;
break;
} //switch
} //if
} //if
} //if
What I'd like to have happen when a wall spawns on top of a coin is have it so that the coin gets "deleted" (in this case just moved from its location in the wall to its original spawn point off screen since its all in a coin "pool")
All help will be appreciated.
This can be accomplished using Collider or in your case, probably Collider2D.
I'm guessing that you're already using colliders to detect if your player hits the coin or wall, so just add in logic to detect if the colliding object is a column or a player.
void OnTriggerEnter2D(Collider2D col)
{
if(col.name == "playerObject"){
//Increase coins?
}
this.respawn();
}
So I edited my question because I have forgotten to show you a camera script. Maybe the problem is somewhere there. I just believe that even after editing the old question there will absolutely no people who read edited article. So I've created a new question.
So I have such a problem. I try to make a tram moving. To do it I downloaded a script from Asset Store "Bezier Path Creator": https://assetstore.unity.com/packages/tools/utilities/b-zier-path-creator-136082. It works nice. Before the need of creating third person camera. After writing a short script I saw that vehicle is twitching after getting some speed. I sat a couple of days trying to solve this problem and I saw one thing. If to remove * Time.deltaTime there are no twitching anymore but there is dependence on FPS (what was predictable). Also if to click Pause button and look frame by frame there are no twitching. What can I do about it?
There are some pieces of code I have problems with:
switch (acceleration) {
case -1:
acc = -12F;
break;
case -2:
acc = -15F;
break;
case -3:
acc = -18F;
break;
case 0:
acc = 0.000f;
break;
case 1:
acc = 9f;
break;
case 2:
acc = 12f;
break;
case 3:
acc = 17.1f;
break;
}
if (Input.GetKeyDown ("e")) {
acceleration++;
}
if (Input.GetKeyDown ("q")) {
acceleration--;
}
if (acceleration < -3) {
acceleration = -3;
}
if (acceleration > 3) {
acceleration = 3;
}
if (speed > 40.0f) {
speed = 40.0f;
saveSpeed = speed;
speed = saveSpeed;
} else if (speed >= 0.0f && speed <= 0.03f && acceleration == 0) {
speed = 0.0f;
} else if (speed <= 0.0f && speed >= -0.03f && acceleration == 0) {
speed = 0.0f;
} else if (speed <= 40.0f) {
speed += ((Time.time - startTime)/1000)*(-acc);
}
// Taking a piece of Asset Store code
transform.rotation = pathCreator.path.GetRotationAtDistance(distanceTravelled);
transform.position = pathCreator.path.GetPointAtDistance(distanceTravelled); // I guess the problem is somewhere there
So there are GetRotationAtDistance and GetPointAtDistance methods from Asset Store script:
public Vector3 GetPointAtDistance(float dst, EndOfPathInstruction endOfPathInstruction = EndOfPathInstruction.Loop)
{
float t = dst / length;
return GetPoint(t, endOfPathInstruction);
}
public Vector3 GetPoint(float t, EndOfPathInstruction endOfPathInstruction = EndOfPathInstruction.Loop)
{
var data = CalculatePercentOnPathData(t, endOfPathInstruction);
return Vector3.Lerp(vertices[data.previousIndex], vertices[data.nextIndex], data.percentBetweenIndices);
}
public Quaternion GetRotationAtDistance(float dst, EndOfPathInstruction endOfPathInstruction = EndOfPathInstruction.Loop)
{
float t = dst / length;
return GetRotation(t, endOfPathInstruction);
}
public Quaternion GetRotation(float t, EndOfPathInstruction endOfPathInstruction = EndOfPathInstruction.Loop)
{
var data = CalculatePercentOnPathData(t, endOfPathInstruction);
Vector3 direction = Vector3.Lerp(tangents[data.previousIndex], tangents[data.nextIndex], data.percentBetweenIndices);
Vector3 normal = Vector3.Lerp(normals[data.previousIndex], normals[data.nextIndex], data.percentBetweenIndices);
return Quaternion.LookRotation(direction, normal);
}
Script of camera:
using UnityEngine;
using System.Collections;
public class CameraRotateAround : MonoBehaviour {
public GameObject target;
public Vector3 offset;
public float sensitivity = 3; // чувствительность мышки
public float limit = 80; // ограничение вращения по Y
public float zoom = 0.25f; // чувствительность при увеличении, колесиком мышки
public float zoomMax = 10; // макс. увеличение
public float zoomMin = 3; // мин. увеличение
private float X, Y;
void Start ()
{
limit = Mathf.Abs(limit);
if(limit > 90) limit = 90;
offset = new Vector3(offset.x, offset.y, -Mathf.Abs(zoomMax)/2);
transform.position = target.transform.position + offset;
offset.z -= zoom + 3;
}
void Update ()
{
if(Input.GetAxis("Mouse ScrollWheel") > 0) offset.z += zoom;
else if(Input.GetAxis("Mouse ScrollWheel") < 0) offset.z -= zoom;
offset.z = Mathf.Clamp(offset.z, -Mathf.Abs(zoomMax), -Mathf.Abs(zoomMin));
X = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivity;
Y += Input.GetAxis("Mouse Y") * sensitivity;
Y = Mathf.Clamp (Y, -limit, 0);
transform.localEulerAngles = new Vector3(-Y, X, 0);
transform.localPosition = transform.localRotation * offset + target.transform.position;
}
}
Hope somebody'll help me this time because I really don't know what can I do to fix this bag.
I once had a similar problem and This link Helped me out a ton.
The problem you are experiencing is due to The camera being 3rd person and not parented to the object it is following.
The problem is that the target object when moved, moves before the camera, thus causing the stutter, as the camera moves just after the object. Try putting the camera script in LateUpdate, but if that does not work, then I suggest checking the link I have linked above.
The link talks about interpolation, which, without increasing your physics timestep, moves the camera to a position which the provided asset calculates the camera will be at, thus removing the stutter and achieving smooth motion. Check the link for the full info
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.