I have 2 function that create balls. One create blue ball every 1 sec and the other creates red ball every 4 sec. I wish to add them togeteher. Because if game over the action is the same, and I actually do not need 2 funcs. So how can I combine the together in one function.
void Start ()
{
StartCoroutine(CreateBall());
StartCoroutine(CreateBall_Red());
gameOver = false;
}
IEnumerator CreateBall()
{
while(true)
{
GameObject particlePop1 = (GameObject)GameObject.Instantiate(ball);
particlePop1.transform.position = new Vector3(Random.Range(-9f, 9f), 6,0);
yield return new WaitForSeconds(1);
if (gameOver)
{
//restartText.text = "Press 'R' for Restart";
//restart = true;
break;
}
}
}
IEnumerator CreateBall_Red()
{
while(true)
{
GameObject particlePop1 = (GameObject)GameObject.Instantiate(ball_Red);
particlePop1.transform.position = new Vector3(Random.Range(-9f, 9f), 6,0);
yield return new WaitForSeconds(4);
if (gameOver)
{
break;
}
}
}
Make this change in that both functions
if (gameOver)
{
//restartText.text = "Press 'R' for Restart";
//restart = true;
yield return new WaitForSeconds(0);
break;
}
else
{
yield return new WaitForSeconds(4);// For blue ball yield return new WaitForSeconds(1);
}
You could make a single function with two parameters:
IEnumerator CreateBall(GameObject prefab, float waitTime)
{
while(true)
{
GameObject particlePop1 = (GameObject)GameObject.Instantiate(prefab);
particlePop1.transform.position = new Vector3(Random.Range(-9f, 9f), 6,0);
yield return new WaitForSeconds(waitTime);
// Other stuff here
}
}
and then simply call:
StartCoroutine(CreateBall(ball, 1));
StartCoroutine(CreateBall(ball_Red, 4));
Making it much more flexible!
Related
I'm working on some script and I have the following two coroutines:
private IEnumerator blockTimer(float duration)
{
blocking = true;
yield return new WaitForSeconds(duration);
blocking = false;
movementCooldown = true;
sprite.color = Color.green;
yield return new WaitForSeconds(duration);
movementCooldown = false;
sprite.color = Color.white;
yield return null;
}
private IEnumerator dashTimer(float duration)
{
dashing = true;
yield return new WaitForSeconds(duration);
dashing = false;
movementCooldown = true;
sprite.color = Color.green;
yield return new WaitForSeconds(duration);
movementCooldown = false;
sprite.color = Color.white;
yield return null;
}
They are called in my update function upon different inputs:
private void Update()
{
if (dashing || blocking || movementCooldown) return;
if (Input.GetButtonDown("Dash") & (movementX!=0||movementY!=0))
{
sprite.color = Color.red;
StartCoroutine(dashTimer(dashTime));
}
if (Input.GetButtonDown("Block"))
{
sprite.color = Color.blue;
StartCoroutine(blockTimer(blockTime));
}
}
Obviously, these two coroutines are very similar. I've been playing around with some different ways to generalize them. I just can't figure out how I'm meant to pass a bool as a parameter into one general coroutine and set it from within. I can set the booleans by pointing directly to them but how do I make it so I can call on a parameter bool and update it during the coroutine? Any help is much appreciated!
You can use a call back function as a parameter, like this :
private IEnumerator GenericTimer(float duration, Func<bool, bool> callback)
{
callback(true);
yield return new WaitForSeconds(duration);
callback(false);
movementCooldown = true;
sprite.color = Color.green;
yield return new WaitForSeconds(duration);
movementCooldown = false;
sprite.color = Color.white;
}
And then you just make a lambda that assign this value to either blocking or dashing variables:
private void Update()
{
if (dashing || blocking || movementCooldown) return;
if (Input.GetButtonDown("Dash") & (movementX!=0||movementY!=0))
{
sprite.color = Color.red;
StartCoroutine(GenericTimer(dashTime, (bool value) => dashing = value));
}
if (Input.GetButtonDown("Block"))
{
sprite.color = Color.blue;
StartCoroutine(GenericTimer(blockTime, (bool value) => blocking = value));
}
}
Guys When I gave it something tagged with pizza first coroutine doesn't stop How Can I stop it?
Please help me guys I couldn't find the way. What should I do? Btw I am new sorry for bad posting:/
I'm trying to make a pizza restaurant game. So customer will sit then waitforpizza coroutine will start if we give tag with pizza waitforpizza coroutine should start then eatpizza will start but my waitforpizza doesn't stop.
IEnumerator EAT, PAY, WAIT;
private void Start()
{
EAT = EatPizza();
WAIT = WaitForPizza();
PAY = WaitForTheCase();
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Pizza"))
{
canEat = true;
}
if (other.gameObject.CompareTag("Out"))
{
Destroy(this.gameObject);
}
}
void Update()
{
if (isEating)
{
if (Vector3.Distance(transform.position, agent.destination) <= 1f)
{
anim.SetTrigger("sit");
isEating = false;
}
}
if (!isEating && !isPaying && !isOut && !canEat)
{
StartCoroutine(WaitForPizza());
}
if (!isEating && !isPaying && !isOut && canEat)
{
StopCoroutine(WAIT);
StartCoroutine(EatPizza());
}
if (isPaying)
{
isEating = false;
anim.SetTrigger("walk");
agent.destination = checkoutTarget.position;
if (Vector3.Distance(transform.position, agent.destination) <= 1f)
{
anim.SetTrigger("wait");
if (ifCashier)
{
//throw money
isPaying = false;
isOut = true;
}
if (!ifCashier)
{
StartCoroutine(WaitForTheCase());
}
}
}
if (isOut)
{
anim.SetTrigger("walk");
isEating = false;
isPaying = false;
agent.destination = outTarget.position;
}
if (canEat)
{
StopCoroutine(WAIT);
}
}
IEnumerator WaitForTheCase()
{
anim.SetTrigger("wait");
yield return new WaitForSeconds(randomFloatWait);
angry.SetActive(true);
isEating = false;
isPaying = false;
isOut = true;
}
IEnumerator EatPizza()
{
angry.SetActive(false);
StopCoroutine(WaitForPizza());
happy.SetActive(true);
yield return new WaitForSeconds(randomFloatWait);
happy.SetActive(false);
isEating = false;
isPaying = true;
isOut = false;
}
IEnumerator WaitForPizza()
{
while (!canEat)
{
yield return new WaitForSeconds(randomFloatWait);
angry.SetActive(true);
isEating = false;
isPaying = false;
isOut = true;
}
}
First, define WAIT as Coroutine then when you want to start waiting use WAIT = StartCoroutine(WaitForPizza()); and when you want to finish it use StopCoroutine(WAIT);.
Im trying to start and end a coroutine with a button. I can start the coroutine but I cant stop it, if I click the button again after the first time starting the coroutine it just restarts again and the slider value goes up.
heres my code
public void LoopButton(){
if (lb == 1){
StopCoroutine (AutoLoop());
tb--;
} else {
StartCoroutine (AutoLoop ());
tb++;
}
}
IEnumerator AutoLoop(){
slider.value = slider.minValue;
while(slider.value < slider.maxValue){
slider.value++;
yield return new WaitForSeconds(0.5f);
}
StartCoroutine (AutoLoop());
}
You need to call StopCoroutine with a reference to the same Coroutine returned by StartCoroutine, like this:
private Coroutine loopCoroutine;
public void LoopButton()
{
if (lb == 1)
{
StopCoroutine(loopCoroutine);
tb--;
}
else
{
loopCoroutine = StartCoroutine(AutoLoop());
tb++;
}
}
To use this approach, change your AutoLoop method to use a while loop rather than a starting another AutoLoop coroutine at the end of the method. Otherwise, you will not be able to stop this new coroutine that is started at the end of AutoLoop.
IEnumerator AutoLoop()
{
while(true)
{
slider.value = slider.minValue;
while (slider.value < slider.maxValue)
{
slider.value++;
yield return new WaitForSeconds(0.5f);
}
}
}
For an alternate solution, as another user commented, it's also possible to stop the coroutine via a boolean flag:
private bool stopLoop;
public void LoopButton()
{
if (lb == 1)
{
stopLoop = true;
tb--;
}
else
{
stopLoop = false;
StartCoroutine (AutoLoop ());
tb++;
}
}
IEnumerator AutoLoop()
{
slider.value = slider.minValue;
while (slider.value < slider.maxValue && !stopLoop)
{
slider.value++;
yield return new WaitForSeconds(0.5f);
}
if (!stopLoop)
{
StartCoroutine(AutoLoop());
}
}
However, using Unity's StopCoroutine is preferable to using a boolean flag for readability & cleanliness.
You can use StopCoroutine.
More info here:
https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopCoroutine.html
Use string for coroutine name. Like this:
public void LoopButton(){
if (lb == 1){
StopCoroutine ("AutoLoop");
tb--;
} else {
StartCoroutine ("AutoLoop");
tb++;
}
}
IEnumerator AutoLoop(){
slider.value = slider.minValue;
while(slider.value < slider.maxValue){
slider.value++;
yield return new WaitForSeconds(0.5f);
}
StartCoroutine ("AutoLoop");
}
I have a method to start a coroutine, and should stop it and reset some things before starting it again.
private Coroutine wholeTutorialRoutine;
public void RunWholeTutorial()
{
tutorialText.text = "";
StopAllCoroutines();
if(wholeTutorialRoutine != null)
{
StopCoroutine(wholeTutorialRoutine);
}
wholeTutorialRoutine = StartCoroutine(WholeTutorial());
}
private IEnumerator WholeTutorial()
{
// Wait until after we are done showing this dialouge
yield return StartCoroutine(ShowDialougForSeconds("tap_to_kill", 5f));
yield return new WaitForSeconds(5f);
yield return StartCoroutine(ShowDialougForSeconds("larger_enemies", 5f));
yield return new WaitForSeconds(5f);
yield return StartCoroutine(ShowDialougForSeconds("press_button", 7f));
yield return new WaitForSeconds(3f);
yield return StartCoroutine(ShowDialougForSeconds("button_colors", 5f));
}
private IEnumerator ShowDialougForSeconds(string diagID, float time)
{
SetText(diagID);
tutorialText.GetComponent<Animator>().SetTrigger("FadeIn");
yield return new WaitForSeconds(time);
tutorialText.GetComponent<Animator>().SetTrigger("FadeOut");
}
wholeTutorialRoutine is a private field of type Coroutine.
I feel like there is something funky happening with those WaitForSeconds calls, but I am not quite sure what.
RunWholeTutorial() is hooked up to a button, so I want to stop the current tutorial, and start again if the user presses it over and over again.
What happens currently seems to be that the coroutines run on top of one another.
Use IEnumerator instead of Coroutine to store the instance of the RunWholeTutorial coroutine function once in the Start function. You can then be able to start and stop it with that IEnumerator variable.
private IEnumerator wholeTutorialRoutine;
void Start()
{
wholeTutorialRoutine = WholeTutorial();
}
public void RunWholeTutorial()
{
tutorialText.text = "";
if (wholeTutorialRoutine != null)
{
StopCoroutine(wholeTutorialRoutine);
}
StartCoroutine(wholeTutorialRoutine);
}
private IEnumerator WholeTutorial()
{
// Wait until after we are done showing this dialouge
yield return StartCoroutine(ShowDialougForSeconds("tap_to_kill", 5f));
yield return new WaitForSeconds(5f);
yield return StartCoroutine(ShowDialougForSeconds("larger_enemies", 5f));
yield return new WaitForSeconds(5f);
yield return StartCoroutine(ShowDialougForSeconds("press_button", 7f));
yield return new WaitForSeconds(3f);
yield return StartCoroutine(ShowDialougForSeconds("button_colors", 5f));
}
private IEnumerator ShowDialougForSeconds(string diagID, float time)
{
SetText(diagID);
tutorialText.GetComponent<Animator>().SetTrigger("FadeIn");
yield return new WaitForSeconds(time);
tutorialText.GetComponent<Animator>().SetTrigger("FadeOut");
}
public class green : MonoBehaviour
{
private AudioSource source;
public AudioClip sound;
static int result = 0;
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("a");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
Thread.Sleep(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
yield return new WaitForSeconds(3f * 60f);
gm.life -= 1;
Debug.Log("z");
}
public void Update()
{
if (result == 1 && gm.checka == true)
{
Debug.Log("e");
StopCoroutine("RoutineCheckInputAfter3Minutes");
gm.life += 1;
source.Stop();
gm.checka = false;
Debug.Log("j");
}
if (result == 2 && gm.checkb == true)
{
Debug.Log("f");
StopCoroutine("RoutineCheckInputAfter3Minutes");
gm.life += 1;
source.Stop();
gm.checkb = false;
Debug.Log("z");
}
else if (result == 3 && gm.checkc == true)
{
StopCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("g");
gm.life += 1;
source.Stop();
gm.checkc = false;
Debug.Log(gm.life);
}
}
}
There are two problems
I want to make music stop and life variable decrease -1, if the user doesn't push any buttons for 3 minutes. But if the user pushes the right button, life variable will be increased + 1. but I don't know how to get null input from the user for 3 minutes.
If I use while for this program, this shuts down… until life is below 0, I want to repeat music which is played on irregular time.
Edit: Don't use Thread in Unity
How Unity works
Alternative to Thread
Couroutine Example 1
Coroutine Example 2
* To put it simple, Thread.Sleep hangs to Unity and Unity can't operate for the time, and that's why it looks like running slow.
You can use coroutines for this problem.
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
yield return new WaitForSeconds(3f*60f);
gm.life -= 1;
}
void RightButtonClicked()
{
gm.life += 1;
StopCoroutine("RoutineCheckInputAfter3Minutes");
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
Or, you can just turn your a function into a coroutine, if the other code sections work.
void Start()
{
StartCoroutine(a());
}
public IEnumerator a()
{
while (gm.life >= 0)
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
yield return new WaitForSeconds(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
}
}
This is an example usage of coroutine based on your code More than this is out of scope:
A pastebin link to code