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.
Related
In my scene design, i have a cube and i want to click the cube to start the game. In the Start() function, i have two invoke function, but i don't know how to invoke them until i clicked the cube. Actually
Currently, my Start function is shown as below. And i tried to use a IEnumerator function to solve this. Also shown as below. And in another script which is in the Cube object, i wanna change the static bool start in other script when OnMouseDown().
public class Progress : MonoBehaviour
{
public bool start = false;
// Use this for initialization
void Start()
{
StartCoroutine(Begin());
Invoke("startCycle", 3);
Invoke("startCycle", 15);
}
void Start()
{
//StartCoroutine(Begin());
Invoke("startCycle", 3);
Invoke("startCycle", 15);
}
IEnumerator Begin()
{
while(!start){
yield return null;
}
}
}
and
public class CursorClick : MonoBehaviour
{
void OnMouseDown()
{
Progress.start = true;
}
}
However, it just doesn't work, the invoke still will happen even though i didn't clicked the cube. Plz help!
StartCoroutine(Begin());
starts the Begin() Coroutine but doesn't wait for it to finish. Since your Start is defined as void it simply runs through all the code without waiting for anything.
Either move the calls you want to wait with into the coroutine and for better readability use WaitUntil like
private void Start()
{
StartCoroutine(Begin());
}
private IEnumertor Begin()
{
return new WaitUntil(() => start);
Invoke("startCycle", 3);
Invoke("startCycle", 15);
}
Or - though it is not really documented - you can simply directly convert the Start itself into a Coroutine
private IEnumerator Start()
{
return new WaitUntil(() => start);
Invoke("startCycle", 3);
Invoke("startCycle", 15);
}
If Start is implemented as IEnumertor Unity internally automatically calls it as a Coroutine. You can actually see it in the example for Start
This is not the full script. I am only showing the part which I have problem with.
Issue Faced:
I wanted to make neat and clean script therefore I only call functions into my update.
I wanted to introduce (StartGameFreezeMovement) function into the first line of update.
I couldn't do it. Like the rest of the functions because this one has a timer in it.
Result Wanted:
My intention is to find a way for the first function in update to completely finish then load or activate the rest.
How can I achieve this?
public class PlayerController : MonoBehaviour {
private CharacterController controller;
public float speed;
private Vector3 moveVector;
private float verticalVelocity;
public float gravity;
private float animationDuration = 3.0f;
public Text text;
private float timer;
//-------------------------------------------------------------------------
void Start ()
{
text.text = "";
controller = GetComponent<CharacterController>();
}
//-------------------------------------------------------------------------
// Update is called once per frame
void Update ()
{
if(Time.time < animationDuration)
{
PlayerMovingForward();
return; //getout of if...
}
StartText();
PlayerMovingForward();
PlayerLeftnRight();
PlayerFalloffGravity();
}
//----------------------------------
void StartGameFreezeMovement()
{
if (Time.time < animationDuration)
{
PlayerMovingForward();
return; //getout of if...
}
}
My intention is to find a way for the first function in update to
completely finished then load or activate the rest.
You need a Coroutine function. The Update function is a void function. You will have to create a coroutine function and start it once then make sure that it doesn't exit so that it will imitate the Update function that is called every frame. This can be done by adding a while loop and yielding every frame.
Finally, turn the StartGameFreezeMovement function from void into a coroutine function, then change the if (Time.time < animationDuration) to while (Time.time < animationDuration) and yield inside it with yield return null; so that other scripts will get chance to execute while waiting for the StartGameFreezeMovement function to finish.
Below is a fixed version of the code from your question:
private void Start()
{
//Start once
StartCoroutine(YieldableUpdate());
}
IEnumerator YieldableUpdate()
{
//Call and wait for the StartGameFreezeMovement function to finish
yield return StartGameFreezeMovement();
//Run forever
while (true)
{
StartText();
PlayerMovingForward();
PlayerLeftnRight();
PlayerFalloffGravity();
//Wait a frame so that Unity doesn't freeze
yield return null;
}
}
IEnumerator StartGameFreezeMovement()
{
while (Time.time < animationDuration)
{
PlayerMovingForward();
//Wait a frame so that Unity doesn't freeze
yield return null;
}
}
If you need to check StartGameFreezeMovement() more than once the move yield return StartGameFreezeMovement(); inside the while (true) loop otherwise this check will only happen once.
You could change your StartGameFreezeMovement to a bool.
bool StartGameFreezeMovement()
{
if (Time.time < animationDuration)
{
PlayerMovingForward();
return true; //getout of if...
}
return false;
}
Then change your update function. And then to keep it clean, use return if you do not pass the boolean check to exit the update function early.
void Update ()
{
if (!StartGameFreezeMovement())
{
return;
}
StartText();
PlayerMovingForward();
PlayerLeftnRight();
PlayerFalloffGravity();
}
I want to wait StartCoroutine callback is executed.
Anyone knows how to do this?
public float getXXX() {
var result;
StartCoroutine(YYY((r) => result = r)); // how to wait this?
return result;
}
private IEnumerator YYY(System.Action<float> callback) {
LinkedList<float> list = new LinkedList<float>();
while(timeleft > 0) {
timeleft -= Time.deltaTime;
list.add(transform.position.magnitude);
yield return new WaitForSeconds (WAITSPAN);
}
callback(list.max());
yeild return true;
}
You can't and shouldn't try to wait or yield for a coroutine function to return from non coroutine function (getXXX function). It will block in that non coroutine function until this function returns preventing other Unity scripts to run.
To wait for a coroutine function(YYY) in the getXXX function, you must also make the function you are making the call and waiting from in a coroutine function. In this case this is theYYY function, so that should be a corutine function too then you can yield it:
public IEnumerator getXXX()
{
float result = 0f;
yield return StartCoroutine(YYY((r) => result = r)); // how to wait this?
//Use the result variable
Debug.Log(result);
}
OR
If you don't want to make the getXXX function a a coroutine function then don't try to wait there. You can still use the result from the YYY coroutine function but don't try to return the result. Just use it to do whatever you want to do in that function:
public void doSomethingXXX()
{
StartCoroutine(YYY((result) =>
{
//Do something with the result variable
Debug.Log(result);
}));
}
The idea of using coroutine is to be able to do something over multiple frames. The void function will just do that in one frame. You can't yield/wait in a void or non IEnumerator/coroutine functio.
You can only wait inside a coroutine. To do this, your getXXX() method should also be a coroutine. Something like this:
public float someOtherMethod()
{
float result;
StartCoroutine(getXXX(out result));
return result;
}
IEnumerator getXXX(out float result)
{
//more code here...
yield return StartCoroutine(YYY((r) => result = r));
//more code here...
}
IEnumerator YYY(System.Action<float> callback)
{
//your logic here...
}
I found something you may be able to call the class and use the methods inside this code and modify to use this is very similar to your code but less complex:
using UnityEngine;
using System.Collections;
public class WaitForSecondsExample : MonoBehaviour
{
void Start()
{
StartCoroutine(Example());
}
IEnumerator Example()
{
print(Time.time);
yield return new WaitForSeconds(5);
print(Time.time);
}
}
this code was taken from: https://docs.unity3d.com/ScriptReference/WaitForSeconds.html
from there examples
The 5 is the amount of time it will wait unless you want to do this dynamically based upon something. Depends on what you want to do. However notice how they are calling the method Example() inside the StartCoroutine(Example()) and which will go to the IEnumerator Example() and within there you have WaitForSeconds(5); this will make the StartCoroutine wait for 5 seconds. This can be hardcoded or made to wait dynamically by calling another method within that class from within IEnumerator Example() this is just one of many ways you can attack this. Again depends on what you want to do. Actually, you might even be better off making this into a method that passes a value in to the method each time something like
IEnumerator Example(float flSeconds)
{
print(Time.time);
yield return new WaitForSeconds(flSeconds);
print(Time.time);
}
this way you can pass what is in your
LinkedList list = new LinkedList();
Every time
I need to create a infinite loop in Unity without using the main thread? I saw some example, but it's not usefull:
while(true){
var aa;
debug.log("print.");
}
I want to add some delay like e.g. 2 seconds. If anybody knows the solution please help.
First define a Coroutines:
private IEnumerator InfiniteLoop()
{
WaitForSeconds waitTime = new WaitForSeconds(2);
while (true)
{
//var aa;
Debug.Log("print.");
yield return waitTime;
}
}
Then call it like that:
StartCoroutine(InfiniteLoop());
Added note:
If you happen to change Time.timeScale and don't want that to affect delay time, use:
yield return new WaitForSecondsRealtime(2);
Use this to create the loop;
private IEnumerator LoopFunction(float waitTime)
{
while (true)
{
Debug.Log("print.");
yield return new WaitForSeconds(waitTime);
//Second Log show passed waitTime (waitTime is float type value )
Debug.Log("print1.");
}
}
For calling the function, don't use Update() or FixedUpdate(), use something like Start() so you don't create infinite instances of the loop;
void Start()
{
StartCoroutine(LoopFunction(1));
}
Use coroutines..
//Call in your Method
StartCoroutine(LateStart(2.0f));
Then write coroutine like..
private IEnumerator LateStart(float waitTime)
{
yield return new WaitForSeconds(waitTime);
//After waitTime, you can use InvokeRepeating() for infinite loop infinite loop or you use a while(true) loop here
InvokeRepeating("YourRepeatingMethod", 0.0f, 1.0f);
}
Here is the documentation for InvokeRepeating():
https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html
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());