Delay within an if in C# - c#

How can I create a delay after the fade in, so that the text stays on screen for a few seconds? I used an IEnumerator and a coroutine, but it does nothing. I also tried placing it right after the first else.
What happens at the moment is the text fades out before having the chance to fade in. The text appears momentarily in semi-clear and disappears. It's for a Unity project.
Also, Thread.Sleep won't do.
Here's the piece of code in question:
IEnumerator Pause ()
{
yield return new WaitForSecondsRealtime(5);
}
void OnTriggerStay2D(Collider2D interCollider)
{
if (Input.GetKeyDown(KeyCode.E))
{
displayInfo = true;
}
else
{
displayInfo = false;
}
}
void FadeText()
{
if (displayInfo == true)
{
text1.text = string1;
text1.color = Color.Lerp(text1.color, Color.white, fadeTime * Time.deltaTime);
}
else
{
StartCoroutine(Pause());
text1.color = Color.Lerp(text1.color, Color.clear, fadeTime * Time.deltaTime);
}
}

Your code should read:
void Update()
{
if (fadingOut)
{
// fade out with lerp here
}
}
IEnumerator Pause()
{
yield return new WaitForSecondsRealtime(5);
fadingOut = true;
}
void FadeText()
{
if (displayInfo == true)
{
text1.text = string1;
text1.color = Color.Lerp(text1.color, Color.white, fadeTime * Time.deltaTime);
}
else
{
StartCoroutine(Pause());
}
}
You have the right idea of using a coroutine, but didn't quite get the execution right. When you invoke a method on coroutine, it will be executed in parallel with the main thread. In your code, the Pause() method is running alongside the Color.Lerp. If you want the fading to wait until after the pause is complete, they must be on the same coroutine.
Edit:
As pointed out, this won't work if you're calling FadeText() on each frame. But this shows you how you can easily set a flag and wait until the pause time is complete before fading.

You just need to add the text fade to the coroutine.
IEnumerator Pause()
{
yield return new WaitForSecondsRealtime(5);
text1.color = Color.Lerp(text1.color, Color.clear, fadeTime * Time.deltaTime);
}
And just start the coroutine in your else statement. This way it will execute the wait for seconds, and then the fade whenever you call it.

Most easy way is to use LeanTween asset. It's free and have a lot of other usefull features that I use in EVERY project.
It's really awesome lib.
LeanTween.DelayedCall(1f,()=>{ /*any code that will be called after 1 second will pass*/ });
or
LeanTween.DelayedCall(1f, SomeMethodWithoutParams());

Related

How come this simple random jumping script doesn't work?

so I am currently creating a simple platformer enemy that is meant to jump at random intervals, I want the enemy to do it every 2-5 seconds. While this script should work in theory (I cannot see anything wrong with it) when I run Unity, the enemy just doesn't move. I added in the Debug.Log() lines to try to figure if it was running but the force was too small or to see if it was getting stuck in the waiting state, however the console repeats nothing but "Not Waiting". So it never even runs the Delay in the first place.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JumperMovement : MonoBehaviour
{
Rigidbody2D rb;
public float jumpForce;
bool jump = false;
bool waiting = false;
private void Awake()
{
rb = gameObject.GetComponent<Rigidbody2D>();
}
private void Update()
{
if (jump)
{
Vector2 motion = new Vector2(0f, jumpForce);
rb.AddForce(motion, ForceMode2D.Impulse);
Debug.Log("Jumping");
jump = false;
Delay();
} else if (!waiting)
{
Debug.Log("Not Waiting");
Delay();
}
}
IEnumerator Delay()
{
waiting = true;
int delay = Random.Range(2, 6);
Debug.Log("Waiting");
yield return new WaitForSeconds(delay);
jump = true;
waiting = false;
}
}
I also tried to just put all the code into a loop in the co-routine but I got the same result. I've not used them much so don't know much about them so if someone can explain why this doesn't work as well that would be super useful.
IEnumerator Delay()
{
while (true)
{
int delay = Random.Range(2, 6);
yield return new WaitForSeconds(delay);
Vector2 motion = new Vector2(0f, jumpForce);
rb.AddForce(motion, ForceMode2D.Impulse);
}
}
There's a couple of things causing issues here:
Coroutines should be started with the StartCoroutine(coroutine) method, else they will be ran as normal code, which is why waiting seems to always be false. (Delay() is ran without pausing, meaning waiting = true and waiting = false happens immediately)`
RigidBody.AddForce is a physics operation, meaning it should be ran within the FixedUpdate method, and not in the normal Update method. If you want to run AddForce inside the Coroutine, use yield return new WaitForFixedUpdate()

Why coroutine is not working properly in Unity?

Sometimes when I step on a red box the timer doens't stop and the buff is always on. Why is this happening? I think this is something related with the couroutines, but I can't figure why. Here is the main code:
private void OnCollisionEnter(Collision coll)
{
if (coll.transform.CompareTag("Player") && !_isFalling)
{
StartCoroutine(HexFalling());
if (type == HexGrid.TypeHex.good)
{
StartCoroutine(coll.gameObject.GetComponent<ThirdPersonMovement>().BuffSpeed(3f, 0.5f));
}
else if (type == HexGrid.TypeHex.bad)
{
StartCoroutine(coll.gameObject.GetComponent<ThirdPersonMovement>().BuffSpeed(0.5f, 1.5f));
}
}
}
And here is the code for one coroutine:
private IEnumerator HexFalling()
{
GetComponent<Renderer>().material = _matIsFalling;
yield return new WaitForSeconds(_timeToFall);
_isFalling = true;
gameObject.SetActive(false);
}
You are deactivating the object that is used for running your coroutine. It is interrupting the coroutine execution.
Also, your coroutine HexFalling() can be called multiple times because _isFalling is not set to true immediately. It will be set to true only in _timeToFall seconds after the collision.

How can i make my caroutine run in every x seconds

I created a caroutine, and i want it to run in every x seconds. i tried using while loop but it didn't worked for this caroutine. can anybody please help ? thanks.
IEnumerator StartFire()
{
{
Firing = true;
animator.SetBool("isFiring", true);
yield return new WaitForSeconds(2);
Firing = false;
animator.SetBool("isFiring", false);
}
}
I think you would be better off using InvokeRepeating(string methodName, float time, float repeatRate). You only need to call it once and it will repeat.
Example:
void Start()
{
InvokeRepeating("myTask", 1.5f, 1.5f);
}
void myTask()
{
// Execute repetitive task.
}
If you want to stop it at any point you simply have to call: CancelInvoke(string methodName);.
Example:
void Update()
{
if (Input.GetKeyDown(KeyCode.S))
CancelInvoke();
}
This would put an end to the repetitive task.

Move GameObject to new position overtime [duplicate]

I am learning Unity from a Swift SpriteKit background where moving a sprite's x Position is as straight forward as an running an action as below:
let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0)
let delayAction = SKAction.waitForDuration(1.0)
let handSequence = SKAction.sequence([delayAction, moveLeft])
sprite.runAction(handSequence)
I would like to know an equivalent or similar way of moving a sprite to a specific position for a specific duration (say, a second) with a delay that doesn't have to be called in the update function.
gjttt1's answer is close but is missing important functions and the use of WaitForSeconds() for moving GameObject is unacceptable. You should use combination of Lerp, Coroutine and Time.deltaTime. You must understand these stuff to be able to do animation from Script in Unity.
public GameObject objectectA;
public GameObject objectectB;
void Start()
{
StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f));
}
bool isMoving = false;
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
isMoving = false;
}
Similar Question: SKAction.scaleXTo
The answer of git1 is good but there is another solution if you do not want to use couritines.
You can use InvokeRepeating to repeatedly trigger a function.
float duration; //duration of movement
float durationTime; //this will be the value used to check if Time.time passed the current duration set
void Start()
{
StartMovement();
}
void StartMovement()
{
InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames
durationTime = Time.time + duration; //This is how long the invoke will repeat
}
void MovementFunction()
{
if(durationTime > Time.time)
{
//Movement
}
else
{
CancelInvoke("MovementFunction"); //Stop the invoking of this function
return;
}
}
You can use co-routines to do this. To do this, create a function that returns type IEnumerator and include a loop to do what you want:
private IEnumerator foo()
{
while(yourCondition) //for example check if two seconds has passed
{
//move the player on a per frame basis.
yeild return null;
}
}
Then you can call it by using StartCoroutine(foo())
This calls the function every frame but it picks up where it left off last time. So in this example it stops at yield return null on one frame and then starts again on the next: thus it repeats the code in the while loop every frame.
If you want to pause for a certain amount of time then you can use yield return WaitForSeconds(3) to wait for 3 seconds. You can also yield return other co-routines! This means the current routine will pause and run a second coroutine and then pick up again once the second co-routine has finished.
I recommend checking the docs as they do a far superior job of explaining this than I could here

unity move object over time using Coroutine wont move the object precisely [duplicate]

I am learning Unity from a Swift SpriteKit background where moving a sprite's x Position is as straight forward as an running an action as below:
let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0)
let delayAction = SKAction.waitForDuration(1.0)
let handSequence = SKAction.sequence([delayAction, moveLeft])
sprite.runAction(handSequence)
I would like to know an equivalent or similar way of moving a sprite to a specific position for a specific duration (say, a second) with a delay that doesn't have to be called in the update function.
gjttt1's answer is close but is missing important functions and the use of WaitForSeconds() for moving GameObject is unacceptable. You should use combination of Lerp, Coroutine and Time.deltaTime. You must understand these stuff to be able to do animation from Script in Unity.
public GameObject objectectA;
public GameObject objectectB;
void Start()
{
StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f));
}
bool isMoving = false;
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
isMoving = false;
}
Similar Question: SKAction.scaleXTo
The answer of git1 is good but there is another solution if you do not want to use couritines.
You can use InvokeRepeating to repeatedly trigger a function.
float duration; //duration of movement
float durationTime; //this will be the value used to check if Time.time passed the current duration set
void Start()
{
StartMovement();
}
void StartMovement()
{
InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames
durationTime = Time.time + duration; //This is how long the invoke will repeat
}
void MovementFunction()
{
if(durationTime > Time.time)
{
//Movement
}
else
{
CancelInvoke("MovementFunction"); //Stop the invoking of this function
return;
}
}
You can use co-routines to do this. To do this, create a function that returns type IEnumerator and include a loop to do what you want:
private IEnumerator foo()
{
while(yourCondition) //for example check if two seconds has passed
{
//move the player on a per frame basis.
yeild return null;
}
}
Then you can call it by using StartCoroutine(foo())
This calls the function every frame but it picks up where it left off last time. So in this example it stops at yield return null on one frame and then starts again on the next: thus it repeats the code in the while loop every frame.
If you want to pause for a certain amount of time then you can use yield return WaitForSeconds(3) to wait for 3 seconds. You can also yield return other co-routines! This means the current routine will pause and run a second coroutine and then pick up again once the second co-routine has finished.
I recommend checking the docs as they do a far superior job of explaining this than I could here

Categories