I need to pause some code in an if statement in c#. Thread.Sleep() is NOT what I want as it pauses everything. I just want to temporarily hold the code in an if statement where it is for a few seconds.
I have tried Thread.Sleep() but it is not what I want.
This is in my Update() method.
if (jumps == jumpsToFatigue)
{
// wait for jumpFatigueWait (variable that is in seconds)
jumps = 0f;
}
I want something that can replace the comment that will pause THIS if statement ONLY for the time specified in my variable.
Sorry cant test now but you can try,Edited
IEnumerator WaitForYourSecond()
{
yield return new WaitForSeconds(2f);
jump = 0;
}
void Update()
{
if (jumps == jumpsToFatigue)
{
StartCoroutine("WaitForYourSecond");
}
}
Related
I'm using a Coroutine to set up a repeating delay as follows.
In my Awake I have
StartCoroutine(RandomMove());
And then further down
IEnumerator RandomMove()
{
while (true)
{
// print(Time.time);
yield return new WaitForSeconds(foo);
// print(Time.time);
}
}
where 'foo' is a random float value that I change with every iteration.
Lets say foo is 10 seconds and part way thru the delay I need to reset the delay so it starts 'counting down' from 10 again.
How would I accomplish this? Should I use a Timer instead?
I don't like either of the two existing answers. Here's what I'd do:
Kill and Restart the coroutine:
We'll start with this part of the killer_mech's answer:
Coroutine myCoroutine;
void Awake() {
myCoroutine = StartCoroutine(RandomMove());
}
But we're going to handle the rest differently. killer_mech never did anything with the reference, other than to keep ovewriting it.
Here's what we're doing instead:
public void resetRandomMove() {
StopCoroutine(myCoroutine);
myCoroutine = StartCoroutine(RandomMove());
}
Call this any time you need to reset it.
I would suggest you first store Coroutine in a variable.
Coroutine myCoroutine;
void Awake()
{
myCoroutine = StartCoroutine(RandomMove());
}
and change the coroutine function as
IEnumerator RandomMove()
{
// print(Time.time);
yield return new WaitForSeconds(foo);
// print(Time.time);
// Call your new coroutine here
myCoroutine = StartCoroutine(RandomMove());
}
this way you will have a coroutine variable for every iteration. If you need to stop the coroutine just say :
StopCoroutine(myCoroutine);
in your function at required time.This will allow you to stop a coroutine in middle before the end of countdown. Also at the end of coroutine it will start new coroutine with updated reference After finishing your task just call back again with
myCoroutine = StartCoroutine(RandomMove());
Hope this resolves your problem. Yes you can do it with timer also with a boolean flag the same thing but I think using coroutine is much simpler.
.
Hmmm it could something like this also . Just for my own .
void Start() {
StartCoroutine(RepeatingFunction());
}
IEnumerator RepeatingFunction () {
yield return new WaitForSeconds(repeatTime);
StartCoroutine( RepeatingFunction() );
}
As i understand the question. InvokeRepeating() is also a choice.
Maybe it is because you are each frame waiting for new assigned seconds?
Why don't you make the random before yielding the wait, and store the CustomYieldInstruction instead of yielding a new instance, since it disposes the one that was before, that creates memory problems. You won't notice that if you yield return a WaitForSeconds with a constant value, but maybe with a random one creates ambiguity and resets the timer (see this Unity's optimization page, on the Coroutine's section). A quick example:
public float foo;
public float min;
public float max;
void Awake()
{
StartCoroutine(Countdown());
}
IEnumerator Countdown()
{
while(true)
{
foo = Random.Range(min, max);
WaitForSeconds wait = new WaitForSeconds(foo);
yield return wait;
}
}
Also, #ryeMoss's solution seems a good one, to stop and restart the coroutine if 'foo' changes.
Hope it helps.
I'm creating a Pop up menu Option in Unity. Now my Problem here is that the coroutine i made in void update is being called so many times. What i mean by that is on my Unity Console the Debug.Logs are incrementing . It should not right because its already coroutine. Could some help me understand more coroutine and help me solve my little problem .
Here is my code:
[SerializeField]
GameObject Option;
[SerializeField]
Button btn,btn2;
[SerializeField]
GameObject open, close;
[SerializeField]
GameObject[] opt;
bool startFinding = false;
void Start()
{
Option.SetActive(false);
Button popUp = btn.GetComponent<Button>();
Button popUp2 = btn2.GetComponent<Button>();
popUp.onClick.AddListener(PopUpOption);
popUp2.onClick.AddListener(ClosePopUp);
}
void Update()
{
if (startFinding)
{
StartCoroutine(GameOptions());
}
}
IEnumerator GameOptions()
{
//Get All the tags
opt = GameObject.FindGameObjectsWithTag("MobileOptions");
if (opt[0].GetComponent<Toggle>().isOn == true && opt[1].GetComponent<Toggle>().isOn == true)
{
Debug.Log("Disable first the check box then choose only 1 option between" + "'rendering'"+ "and" + "'livestreaming'");
}
//Livestreaming
if (opt[0].GetComponent<Toggle>().isOn == true)
{
Debug.Log("Livestreaming Activate");
} else
{
Debug.Log("Livestreaming Deactivate");
}
//Rendering
if (opt[1].GetComponent<Toggle>().isOn == true)
{
Debug.Log("Rendering Activate");
} else
{
Debug.Log("Rendering Deactivate");
}
//Fog
if (opt[2].GetComponent<Toggle>().isOn == true)
{
Debug.Log("Fog Activated");
} else
{
Debug.Log("Fog Deactivated");
}
//Camera Effect
if (opt[3].GetComponent<Toggle>().isOn == true)
{
Debug.Log("Camera Effect Activated");
} else {
Debug.Log("Camera Effect Deactivated");
}
yield return null;
}
void PopUpOption()
{
startFinding = true;
//Disable The Mobile Option Button
open.SetActive(false);
//Enable the Close Option Button
close.SetActive(true);
//activate the Mobile Options
Option.SetActive(true);
}
void ClosePopUp()
{
startFinding = false;
//eanble the mobile option button
open.SetActive(true);
//disable the close option button
close.SetActive(false);
//deactivate the Mobile Option
Option.SetActive(false);
}
Here is how coroutines work:
Let's say I have a couroutine function called MyRoutine (in your case, you called it GameOptions)
private IEnumerator MyRoutine()
Then, anywhere in my code, calling
StartCoroutine(MyRoutine));
Is going to simply call MyRoutine like any usual method. So if you call it in update, it will be called all the time, as any method would. This is not what you want. What make coroutines special is that you can use the yield keyword in them. There are many ways to use it but the most used (and simple) one is to do yield return null
yield return null means "Stop this coroutine, but resume the execution on next frame". You don't need to call any other function (certainly not StartCoroutine). The execution will resume next frame.
To go back to what you posted in your question, you wrote yield return null at the end. So your method is executing, and just at the end, stops and resumes next frame, but since there is nothing left to do, it exits on the next frame.
A typical way to use coroutines is to have the yield return null in a while loop, so when it resumes, it continues the loop. Here is an example that do it
private IEnumerator MyRoutine()
{
while(running) //running is a member bool that you could set to false to exit
{
// Do all the stuff you want to do in ONE frame
// ...
yield return null;
}
}
Typically, the StartCoroutine would be called in the Start() function, or later when an event is triggered.
If you want to know more about coroutine, or check that you understood them properly, check out this page: https://docs.unity3d.com/Manual/Coroutines.html
or this video https://unity3d.com/learn/tutorials/topics/scripting/coroutines
// Edit: quickly present one useful option
In the snippet above, the while loop is very similar to the Update function (the inside of the loop is executed each frame). One nice option is to replace
yield return null
by
yield return new WaitForSeconds(waitTime)
where waitTime is a the time you want to wait before resuming, in seconds
// End of edit
Do not use StartCoroutine() in the Update method. Call it in another method and use a while loop inside your coroutine function if needed. Just control your StartCoroutine() outside of Update method
Update is called every frame, if your condition is ever true, you launch your coroutine every frame.
Just set down your flag to only join 1 time.
void Update()
{
if (startFinding)
{
startFinding = false;
StartCoroutine(GameOptions());
}
}
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());
I don't think I fully understand coroutines, it doesn't work the way I wanted, so I need help.
I've got a memory game (Simon like) that consist of 4 squares that randomly switches on and off. After square switches on/off it should take a little break, before switching next button, which my program does not seem to do so. For the switching process I use blink*Colorname coroutine which is following:
foreach (int color in pattern)
{
switch (color)
{
case 0:
StartCoroutine (blinkGreen (blinkSeconds));
break;
case 1:
StartCoroutine (blinkRed (blinkSeconds));
break;
default:
break;
}
}
//to do: pause function between button blinks
IEnumerator blinkGreen (float seconds)
{
greenImg.color = Color.white;
yield return new WaitForSeconds (seconds);
greenImg.color = Color.green;
}
I've tried using waitforseconds at 2 places to achieve my goal: First, at blink*Color as following:
IEnumerator blinkGreen (float seconds)
{
greenImg.color = Color.white;
yield return new WaitForSeconds (seconds);
greenImg.color = Color.green;
yield return new WaitForSeconds (seconds);
}
Second, after the the loop, under //to do: pause function between button blinks by calling another coroutine:
StartCoroutine(waitfornexttransition(5.0f));
IEnumerator waitfornexttransition (float second)
{
yield return new WaitForSeconds (second);
}
Am I missing something? All suggestions and helps are appreciated. Thanks!
Unity does not wait for the completion of the started coroutine to continue code execution. If you type (psuedocode):
print "1"
start coroutine that prints "2" after a second
print "3"
the output will be: "1", "3", "2".
If you put all your code in one coroutine, everything will run sequentially as expected.
Well, since it's all in a foreach loop anyway and you're starting a new couroutine for each iteration, then basically all the coroutines are starting at the same time within the same frame. They will then all run concurrently regardless of what the rest of your code is doing, blinking all lights simultaneously.
If you want your code to wait for a certain amount of time between executions, then make a timer and only blink the lights when the timer hits 0. A basic example would be:
private float timer;
void Start()
{
timer = 2f; // Waiting 2 seconds between blinks
}
void Update()
{
timer -= Time.deltaTime; // Consistently decrement timer independently of frame rate
if (timer <= 0)
{
blinkLight();
timer = 2f;
}
}
void blinkLight()
{
// Light blinking logic goes here.
}
Your foreach loop should also be inside a coroutine and you can put a yield return new WaitForSeconds (seconds) before each iteration.
I want to understand the concept of coroutine i don't know why code stop at when it print 1,2,3.But in this code loop should run 30 times and print value 1 to 30.
public class NewCore : MonoBehaviour
{
void Start ()
{
StartCoroutine (MyCoroutine (0.52f));
StartCoroutine (CoroutineKiller (2f));
}
IEnumerator MyCoroutine (float delay)
{
int value = 0;
while (value < 30)
{
yield return new WaitForSeconds (delay);//wait
value ++;
print (value);
}
StartCoroutine (MyCoroutine (delay));
}
IEnumerator CoroutineKiller (float delay)
{
yield return new WaitForSeconds (delay);
StopAllCoroutines ();
}
}
You are printing values from 1 - 30 with delay of 0.52sec, but after 2 seconds you stop doing so (you call StopAllCoroutines). Which is why you are only seeing 1, 2 and 3 printed out.
Try to comment out StartCoroutine (CoroutineKiller (2f));, or give it more delay to see how it controls the flow stop.
Coroutines are similar to threads - although not really - but yes in the sense that calling StartCoroutine does not block the code.
So when you're doing this:
void Start ()
{
StartCoroutine (MyCoroutine (0.52f));
StartCoroutine (CoroutineKiller (2f));
}
It will actually start both coroutines and execute them step by step, side by side, on each Update call.
If you wish to execute the coroutines one after another, try the following:
void Start()
{
StartCoroutine(F());
}
IEnumerator F()
{
// by yielding the Coroutine, it will block the execution of
// this coroutine (F) until MyCoroutine finishes
yield return StartCoroutine(MyCoroutine(1.52f));
// This is no longer doing much, really.
yield return StartCoroutine(Killer(2f));
print("done");
}
You can read more about the Execution Order which also includes information about coroutines and how the yield system actually works.
It seems you using StopCoroutine(MyCoroutine()); in CoroutineKiller and it stops coroutine after 2 seconds. (your parameter is 2f. And I think you used it for WaitForSeconds). So your MyCoroutine function working just 3 delay ( 0.52 + 0.52 + 0.52 =1.56) and before fourth delay ends, you stop this coroutine and you get just 1,2,3 printed.