How can I put a sleep function between the TextUI.text = ...., to wait 3 seconds between each phrase?
public Text GuessUI;
public Text TextUI;
[...truncated...]
TextUI.text = "Welcome to Number Wizard!";
TextUI.text = ("The highest number you can pick is " + max);
TextUI.text = ("The lowest number you can pick is " + min);
I already tried various things but none have worked, such as this:
TextUI.text = "Welcome to Number Wizard!";
yield WaitForSeconds (3);
TextUI.text = ("The highest number you can pick is " + max);
yield WaitForSeconds (3);
TextUI.text = ("The lowest number you can pick is " + min);
In bash, it would be:
echo "Welcome to Number Wizard!"
sleep 3
echo "The highest number you can pick is 1000"
sleep 3
.....
but I can't figure out how to do this in Unity with C#
There are many ways to wait in Unity. They are really simple but I think it's worth covering most ways to do it:
1.With a coroutine and WaitForSeconds.
This is by far the simplest way. Put all the code that you need to wait for some time in a coroutine function then you can wait with WaitForSeconds. Note that in coroutine function, you call the function with StartCoroutine(yourFunction).
Example below will rotate 90 deg, wait for 4 seconds, rotate 40 deg and wait for 2 seconds, and then finally rotate rotate 20 deg.
void Start()
{
StartCoroutine(waiter());
}
IEnumerator waiter()
{
//Rotate 90 deg
transform.Rotate(new Vector3(90, 0, 0), Space.World);
//Wait for 4 seconds
yield return new WaitForSeconds(4);
//Rotate 40 deg
transform.Rotate(new Vector3(40, 0, 0), Space.World);
//Wait for 2 seconds
yield return new WaitForSeconds(2);
//Rotate 20 deg
transform.Rotate(new Vector3(20, 0, 0), Space.World);
}
2.With a coroutine and WaitForSecondsRealtime.
The only difference between WaitForSeconds and WaitForSecondsRealtime is that WaitForSecondsRealtime is using unscaled time to wait which means that when pausing a game with Time.timeScale, the WaitForSecondsRealtime function would not be affected but WaitForSeconds would.
void Start()
{
StartCoroutine(waiter());
}
IEnumerator waiter()
{
//Rotate 90 deg
transform.Rotate(new Vector3(90, 0, 0), Space.World);
//Wait for 4 seconds
yield return new WaitForSecondsRealtime(4);
//Rotate 40 deg
transform.Rotate(new Vector3(40, 0, 0), Space.World);
//Wait for 2 seconds
yield return new WaitForSecondsRealtime(2);
//Rotate 20 deg
transform.Rotate(new Vector3(20, 0, 0), Space.World);
}
Wait and still be able to see how long you have waited:
3.With a coroutine and incrementing a variable every frame with Time.deltaTime.
A good example of this is when you need the timer to display on the screen how much time it has waited. Basically like a timer.
It's also good when you want to interrupt the wait/sleep with a boolean variable when it is true. This is where yield break; can be used.
bool quit = false;
void Start()
{
StartCoroutine(waiter());
}
IEnumerator waiter()
{
float counter = 0;
//Rotate 90 deg
transform.Rotate(new Vector3(90, 0, 0), Space.World);
//Wait for 4 seconds
float waitTime = 4;
while (counter < waitTime)
{
//Increment Timer until counter >= waitTime
counter += Time.deltaTime;
Debug.Log("We have waited for: " + counter + " seconds");
//Wait for a frame so that Unity doesn't freeze
//Check if we want to quit this function
if (quit)
{
//Quit function
yield break;
}
yield return null;
}
//Rotate 40 deg
transform.Rotate(new Vector3(40, 0, 0), Space.World);
//Wait for 2 seconds
waitTime = 2;
//Reset counter
counter = 0;
while (counter < waitTime)
{
//Increment Timer until counter >= waitTime
counter += Time.deltaTime;
Debug.Log("We have waited for: " + counter + " seconds");
//Check if we want to quit this function
if (quit)
{
//Quit function
yield break;
}
//Wait for a frame so that Unity doesn't freeze
yield return null;
}
//Rotate 20 deg
transform.Rotate(new Vector3(20, 0, 0), Space.World);
}
You can still simplify this by moving the while loop into another coroutine function and yielding it and also still be able to see it counting and even interrupt the counter.
bool quit = false;
void Start()
{
StartCoroutine(waiter());
}
IEnumerator waiter()
{
//Rotate 90 deg
transform.Rotate(new Vector3(90, 0, 0), Space.World);
//Wait for 4 seconds
float waitTime = 4;
yield return wait(waitTime);
//Rotate 40 deg
transform.Rotate(new Vector3(40, 0, 0), Space.World);
//Wait for 2 seconds
waitTime = 2;
yield return wait(waitTime);
//Rotate 20 deg
transform.Rotate(new Vector3(20, 0, 0), Space.World);
}
IEnumerator wait(float waitTime)
{
float counter = 0;
while (counter < waitTime)
{
//Increment Timer until counter >= waitTime
counter += Time.deltaTime;
Debug.Log("We have waited for: " + counter + " seconds");
if (quit)
{
//Quit function
yield break;
}
//Wait for a frame so that Unity doesn't freeze
yield return null;
}
}
Wait/Sleep until variable changes or equals to another value:
4.With a coroutine and the WaitUntil function:
Wait until a condition becomes true. An example is a function that waits for player's score to be 100 then loads the next level.
float playerScore = 0;
int nextScene = 0;
void Start()
{
StartCoroutine(sceneLoader());
}
IEnumerator sceneLoader()
{
Debug.Log("Waiting for Player score to be >=100 ");
yield return new WaitUntil(() => playerScore >= 10);
Debug.Log("Player score is >=100. Loading next Level");
//Increment and Load next scene
nextScene++;
SceneManager.LoadScene(nextScene);
}
5.With a coroutine and the WaitWhile function.
Wait while a condition is true. An example is when you want to exit app when the escape key is pressed.
void Start()
{
StartCoroutine(inputWaiter());
}
IEnumerator inputWaiter()
{
Debug.Log("Waiting for the Exit button to be pressed");
yield return new WaitWhile(() => !Input.GetKeyDown(KeyCode.Escape));
Debug.Log("Exit button has been pressed. Leaving Application");
//Exit program
Quit();
}
void Quit()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
6.With the Invoke function:
You can call tell Unity to call function in the future. When you call the Invoke function, you can pass in the time to wait before calling that function to its second parameter. The example below will call the feedDog() function after 5 seconds the Invoke is called.
void Start()
{
Invoke("feedDog", 5);
Debug.Log("Will feed dog after 5 seconds");
}
void feedDog()
{
Debug.Log("Now feeding Dog");
}
7.With the Update() function and Time.deltaTime.
It's just like #3 except that it does not use coroutine. It uses the Update function.
The problem with this is that it requires so many variables so that it won't run every time but just once when the timer is over after the wait.
float timer = 0;
bool timerReached = false;
void Update()
{
if (!timerReached)
timer += Time.deltaTime;
if (!timerReached && timer > 5)
{
Debug.Log("Done waiting");
feedDog();
//Set to false so that We don't run this again
timerReached = true;
}
}
void feedDog()
{
Debug.Log("Now feeding Dog");
}
There are still other ways to wait in Unity but you should definitely know the ones mentioned above as that makes it easier to make games in Unity. When to use each one depends on the circumstances.
For your particular issue, this is the solution:
IEnumerator showTextFuntion()
{
TextUI.text = "Welcome to Number Wizard!";
yield return new WaitForSeconds(3f);
TextUI.text = ("The highest number you can pick is " + max);
yield return new WaitForSeconds(3f);
TextUI.text = ("The lowest number you can pick is " + min);
}
And to call/start the coroutine function from your start or Update function, you call it with
StartCoroutine (showTextFuntion());
You were correct to use WaitForSeconds. But I suspect that you tried using it without coroutines. That's how it should work:
public void SomeMethod()
{
StartCoroutine(SomeCoroutine());
}
private IEnumerator SomeCoroutine()
{
TextUI.text = "Welcome to Number Wizard!";
yield return new WaitForSeconds (3);
TextUI.text = ("The highest number you can pick is " + max);
yield return new WaitForSeconds (3);
TextUI.text = ("The lowest number you can pick is " + min);
}
With .Net 4.x you can use Task-based Asynchronous Pattern (TAP) to achieve this:
// .NET 4.x async-await
using UnityEngine;
using System.Threading.Tasks;
public class AsyncAwaitExample : MonoBehaviour
{
private async void Start()
{
Debug.Log("Wait.");
await WaitOneSecondAsync();
DoMoreStuff(); // Will not execute until WaitOneSecond has completed
}
private async Task WaitOneSecondAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1));
Debug.Log("Finished waiting.");
}
}
this is a feature to use .Net 4.x with Unity please see this link for description about it
and this link for sample project and compare it with coroutine
But becareful as documentation says that This is not fully replacement with coroutine
Bear in mind that coroutine stack ! If starting your coroutines in Update(), you might end up with loads of coroutines waiting inline and executing almost at the same time, just after your wait.
To avoid this, a good approach is to use a boolean, preventing from "stacking" coroutines :
bool isRunning = false;
IEnumerator MyCoroutine(){
isRunning = true;
print("started");
yield return new WaitForSeconds(3);
print("3 seconds elapsed");
yield return new WaitForSeconds(3);
print("more 3 seconds");
yield return new WaitForSeconds(2);
print("ended");
isRunning = false;
}
void Update(){
if (!isRunning) StartCoroutine(MyCoroutine());
}
Source : https://answers.unity.com/questions/309613/calling-startcoroutine-multiple-times-seems-to-sta.html
here is more simple way without StartCoroutine:
float t = 0f;
float waittime = 1f;
and inside Update/FixedUpdate:
if (t < 0){
t += Time.deltaTIme / waittime;
yield return t;
}
Use async and await
public void Start() {
doTask();
}
async void doTask() {
Debug.Log("Long running task started");
// wait for 5 seconds, update your UI
await Task.Delay(TimeSpan.FromSeconds(5f));
// update your UI
Debug.Log("Long running task has completed");
}
//Here is a example of some of my code to wait in Unity I have made using a value and update dating it every update, once it its the value the if statement is looking for it will run the task.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnterCarCollider : MonoBehaviour
{
public GameObject player;
//Calls & Delcares vehicle objects
public GameObject Camera;
public VehicleControl ascript;
public Collider enterDriverCollider;
public Collider parkBreakCollider;
public GameObject enterVehicleDriverToolTip;
public int forStayInTime = 32;
public int timeInActiveTriggeredCollider;
private void Start()
{
ascript = GetComponent<VehicleControl>();
timeInActiveTriggeredCollider = 0;
}
private void OnTriggerStay(Collider other)
{
if (forStayInTime <= timeInActiveTriggeredCollider)
{
if (Input.GetKey(KeyCode.E))
{
ascript.enabled = !ascript.enabled;
Camera.active = true;
player.active = false;
enterDriverCollider.enabled = false;
parkBreakCollider.enabled = false;
}
// TODO: Enter car message
enterVehicleDriverToolTip.active = true;
}
timeInActiveTriggeredCollider++;
}
private void OnTriggerExit(Collider other)
{
enterVehicleDriverToolTip.active = false;
timeInActiveTriggeredCollider = 0;
}
private void Update()
{
if (enterDriverCollider.enabled is false)
{
timeInActiveTriggeredCollider = 0;
}
}
}
Related
I am trying to set a fire rate in Unity so that when I hold down up arrow, I will shoot a projectile up every 1 second. Currently my code is shooting a projectile every frame update, even though I have a Coroutine set up.
public GameObject bulletPrefab;
public float bulletSpeed;
public float fireRate = 1f;
public bool allowFire = true;
void Update()
{
//shooting input
if (Input.GetKey(KeyCode.UpArrow) && allowFire == true)
{
StartCoroutine(Shoot("up"));
}
}
IEnumerator Shoot(string direction)
{
allowFire = false;
if (direction == "up")
{
var bulletInstance = Instantiate(bulletPrefab, new Vector3(transform.position.x, transform.position.y, transform.position.z + 1), Quaternion.identity);
bulletInstance.GetComponent<Rigidbody>().AddForce(Vector3.forward * bulletSpeed);
}
yield return new WaitForSeconds(fireRate);
allowFire = true;
}
Coroutine
You can use the coroutine, but since you're calling it in an Update loop you much wait for it to finish before starting another one.
Coroutine currentCoroutine;
if(currentCoroutine == null)
currentCoroutine = StartCoroutine(DoShoot());
IEnumerator DoShoot() {
// Shoot.
yield return new WaitForSeconds(1f);
currentCoroutine = null;
}
Timestamp
You can also use a timestamp for when cooldown is ready. It's basically current time plus some duration.
float cooldown = 1f;
float cooldownTimestamp;
bool TryShoot (Vector2 direction) {
if (Time.time < cooldownTimestamp) return false;
cooldownTimestamp = Time.time + cooldown;
// Shoot!
}
I usually end up doing something like:
Variables
[Serializefield] float shootDelay = 1f;
float T_ShootDelay
Start()
T_ShootDelay = shootDelay;
Update()
if(T_ShootDelay < shootDelay)
T_ShootDelay += Time.deltaTime;
ShootInput()
if(T_ShootDelay >= shootDelay)
{
T_ShootDelay = 0;
Shoot();
}
What this does is:
Check if the shootDelay timer is less than the shootDelay.
Add up the timer by 1 per second.
Check the timer's status every time you want to shoot.
Set the timer to 0 after shooting
Considering a M4 AR that fires at least 700 rounds per minute.
700 rounds / 60 (seconds) ~= 11,66 rounds per second
1 second / 11 rounds ~= 0,085 seconds of delay between each round
You could simply try this:
yield return new WaitForSeconds(1 / (fireRate / 60f));
I'm new to unity and I'm developing a 2d game. I want my game to update the "scoretext" every 5 seconds and I want it to update for +1. But my code is not working. It is updating in like 0.000...1 second (I mean the program doesn't wait 5 seconds to update). How can I fix this? Thanks!
public Text scoretext;
public int score;
IEnumerator scoreup()
{
score++;
scoretext.text = score.ToString();
yield return new WaitForSeconds(5);
}
void Update()
{
StartCoroutine("scoreup");
}
Solution 1:
Simple use of InvokeRepeating code:
void ScoreUp()
{
score++;
scoretext.text = score.ToString();
}
void Start()
{
InvokeRepeating(nameof(ScoreUp), 0f, 5f); // 0=delay, 5f = repeat Time
}
Solution 2:
Use an IEnumerator:
IEnumerator ScoreUp(int amount = 1)
{
while (true)
{
score += amount;
scoretext.text = score.ToString();
yield return new WaitForSeconds(5);
}
}
private void Start()
{
StartCoroutine(ScoreUp(2));
}
I have an array of gameobjects that are lights, I'm trying to increase and drecrease range size of a point light over time, problem is lights some times doesn't decrease over time, they just go to range 0 instantly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MainMenu : MonoBehaviour
{
public GameObject[] stars;
private void Start()
{
StartCoroutine(ChooseStar());
}
public void PlayGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
public void QuitGame()
{
Application.Quit();
}
IEnumerator IncreaseRadius(GameObject star, float duration)
{
Debug.Log("Increasing: "+star.name + " radius: " + star.GetComponent<Light>().range);
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
star.GetComponent<Light>().range = counter;
yield return null;
}
StartCoroutine(DecreaseRadius(star));
}
IEnumerator DecreaseRadius(GameObject star)
{
Debug.Log("Decreasing: "+star.name+" radius: "+ star.GetComponent<Light>().range);
float counter = star.GetComponent<Light>().range;
while (star.GetComponent<Light>().range >= 0f)
{
counter -= Time.deltaTime;
star.GetComponent<Light>().range = counter;
yield return null;
}
star.GetComponent<Light>().range = 0f;
}
IEnumerator ChooseStar()
{
float duration = Random.Range(3, 8);
float waitTime = 2f;
GameObject choosenStar = stars[Random.Range(0, stars.Length)];
if (choosenStar.GetComponent<Light>().range <= 0f)
{
StartCoroutine(IncreaseRadius(stars[Random.Range(0, stars.Length)], duration));
}
else
{
waitTime = 0f;
}
yield return new WaitForSeconds(waitTime);
StartCoroutine(ChooseStar());
}
}
the expected result should be this sequence:
1 - pick random star from array of gameobjects
2 - check if the star alredy is being range increased, if yes start again to search a new one if no starts to increase.
3 - light starts increasing until duration, then call decrease function
4 - star starts to decrease, when function is over it reset range to 0
To answer the question in general: You can simply put a
while (true)
{
...
yield return ...
}
around your code. As long as you yield somewhere inside it that's totally valid for Coroutines.
My guess would be that you get concurrent Coroutines because you don't wait for IncreaseRadius to finish before choosing the next random star ... which could be the same as before.
if (chosenStar.range <= 0f)
{
StartCoroutine(IncreaseRadius(stars[Random.Range(0, stars.Length)], duration));
}
else
{
waitTime = 0f;
}
also you do a Random.Range here again although you have already choosen another star before, was this intended?
First in general instead of using GetComponent<Light> all the time over and over again rather simply make
public Light[] stars;
reference the object just in the same way as before but now you are directly dealing with the Light references instead of GameObject.
Then you know that
float duration = Random.Range(3, 8);
actually returns random full int values between 3 and 7. If you rather wanted to have float values also between 3 and 8 so also including e.g. 3.253453f then you should rather use
var duration = Random.Range(3.0f, 8.0f);
Solution 1 - Only one star at a time
As simple alternative you could always animate only one star at a time. You can achieve this by yield return another IEnumerator. That make the other IEnumerator execute and at the same time waits for it to finish. Something like
public Light[] stars;
private void Start()
{
StartCoroutine(ChooseStar());
}
private IEnumerator IncreaseRadius(Light star, float duration)
{
Debug.Log("Increasing: " + star.name + " radius: " + star.range);
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
star.range = counter;
yield return null;
}
// again do the decreasing and at the same time wait for it to finish
yield return DecreaseRadius(star);
}
private static IEnumerator DecreaseRadius(Light star)
{
Debug.Log("Decreasing: " + star.name + " radius: " + star.range);
var counter = star.range;
while (star.range >= 0f)
{
counter -= Time.deltaTime;
star.range = counter;
yield return null;
}
star.range = 0f;
}
IEnumerator ChooseStar()
{
// Looks scary but is totally fine in Coroutines as long as you yield somewhere
// instead of starting a new Coroutine simple continue the one you already have
while (true)
{
var duration = Random.Range(3.0f, 8.0f);
var choosenStar = stars[Random.Range(0, stars.Length)];
// This starts the Increase routine on that star
// and at the same time waits for it to finish!
//
// since we also wait until DecreaseRadius is done this means
// at any time only exactly 1 star is animated at the same time
yield return IncreaseRadius(choosenStar, duration);
}
}
Solution 2 - Filter the random
Alternatively as it looks like you want to allow parallel animations of the stars I would simply filter out the List of available stars (ones that are not currently animated) for getting the random range. Something like
public Light[] stars;
// Use a list for dynamically adding and removing items
private List<Light> availableStars = new List<Light>();
private void Start()
{
// initialize the available list
// copy the references from stars
availableStars.AddRange(stars);
StartCoroutine(ChooseStar());
}
private IEnumerator IncreaseRadius(Light star, float duration)
{
Debug.Log("Increasing: " + star.name + " radius: " + star.range);
// As soon as you start animating this star
// remove it from the list of availables
availableStars.Remove(star);
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
star.range = counter;
yield return null;
}
// Decreasing and at the same time wait for it to finish
yield return DecreaseRadius(star);
// when finished add the star again to the availables
availableStars.Add(star);
}
private static IEnumerator DecreaseRadius(Light star)
{
Debug.Log("Decreasing: " + star.name + " radius: " + star.range);
var counter = star.range;
while (star.range >= 0f)
{
counter -= Time.deltaTime;
star.range = counter;
yield return null;
}
star.range = 0f;
}
IEnumerator ChooseStar()
{
// Looks scary but is totally fine in Coroutines as long as you yield somewhere
while (true)
{
var duration = Random.Range(3.0f, 8.0f);
// in case that currently all stars are being animated
// simply wait until the next one becomes available again
yield return new WaitUntil(() => availableStars.Count > 0);
// Pick a random star from the availables instead
var chosenStar = availableStars[Random.Range(0, availableStars.Count)];
// this check becomes then actually redundant
//if (chosenStar.range <= 0f)
//{
StartCoroutine(IncreaseRadius(chosenStar, duration));
yield return new WaitForSeconds(2f);
//}
}
}
My code:
void Update()
{
//Restart level
if (gameObject.transform.position.y < -0.5)
{
PlayerPrefs.SetInt("CubePointsLvl", 0);
StartCoroutine( Wait3Seconds() );
//rigidbody.AddForce(0,-100000,0);
//transform.position = new Vector3(inputSpawnX, inputSpawnY, inputSpawnZ);
}
}
//Wait 3 second
IEnumerator Wait3Seconds()
{
audio.PlayOneShot(DeadSound, 1.0F);
yield return new WaitForSeconds (0.3f);
Application.LoadLevel(Application.loadedLevel);
}
I want to play a sound when the player is under Y 0.5 position and then the game to restart. But when I debug the code, the sound is looping and I know why, but I don't know how to solve it. How can I do that? And an explication? I am using C#.
You're starting a new coroutine every frame that the player is below -0.5 rather than just doing it once the first time the player goes below -0.5. You could use a flag to prevent the coroutine from being started again.
private bool alreadyDead = false;
public void Update() {
// Only execute if we've gone below -0.5 for the first time
if (gameObject.transform.position.y < -0.5 &&
alreadyDead == false)
{
// Set a flag indicating this has been executed
alreadyDead = true;
PlayerPrefs.SetInt("CubePointsLvl", 0);
StartCoroutine( Wait3Seconds() );
}
}
public IEnumerator Wait3Seconds()
{
audio.PlayOneShot(DeadSound, 1.0F);
yield return new WaitForSeconds (0.3f);
Application.LoadLevel(Application.loadedLevel);
}
My goal: To get my snail to seem like it's moving on its own.
Example: Going right for a few seconds, going left for a few seconds, staying in one place for a few seconds.
Current Status: Snail sits still in one place when I attempt to use WaitForSeconds
Without WaitForSeconds, my snail changes directions back and forth successfully(Except doing this really fast)
I've only started learning Unity and C# yesterday. Any tips/suggestions would be of much help, even if it's not on my original question.
If there's anything else I can do to help you help me, let me know! :)
using UnityEngine;
using System.Collections;
public class SnailMove : MonoBehaviour {
void Start()
{
}
// Use this for initialization
void Update ()
{
Waiting();
}
// Update is called once per frame
void Movement ()
{
int direct = Random.Range(-1, 2);
if (direct == 1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,180);
}
if (direct == -1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,0);
}
}
IEnumerator Waiting()
{
Movement ();
yield return new WaitForSeconds (5);
}
}
Coroutines need to be started with StartCoroutine. From your description it sounds like you want something like this:
using UnityEngine;
using System.Collections;
public class SnailMove : MonoBehaviour
{
public float speed = 1f;
int direction = 0;
void Start()
{
StartCoroutine(ChangeDirection());
}
void Update ()
{
if (direction == 1)
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
transform.eulerAngles = new Vector2(0,180);
}
else if (direction == -1)
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
transform.eulerAngles = new Vector2(0,0);
}
}
IEnumerator ChangeDirection()
{
while(true)
{
yield return new WaitForSeconds (5);
direction = Random.Range(-1, 2); // returns "-1", "0" or "1"
}
}
}
Good day I believe that your problem is that you are calling waiting in your update method that gets called on every frame regardless of previous executions, this implies that only the thread that called waiting before waits and as such the method can be called again as the other thread only waits.
try this:
using UnityEngine;
using System.Collections;
private bool waiting = false;
public class SnailMove : MonoBehaviour {
void Start()
{
}
// Use this for initialization
void Update ()
{
if(waiting == false)
{
Waiting();
}
}
// Update is called once per frame
void Movement ()
{
int direct = Random.Range(-1, 2);
if (direct == 1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,180);
}
if (direct == -1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,0);
}
}
IEnumerator Waiting()
{
Movement ();
waiting = true;
yield return new WaitForSeconds (5);
waiting = false;
}
}
This will make the update function wait for the boolean waiting to be set to false before it will call the function again.
Your logical flow is a little confused. You start the Waiting() coroutine every frame, when you probably want to call it once (in Start() for example) and loop your coroutine. The result is you have a whole bunch of Waiting() coroutines running and all competing with each other.
You have two options here:
void Start() {
StartCoroutine(Waiting());
}
IEnumrator Waiting() {
while(true) {
Movement();
yield return new WaitForSeconds(5f);
}
}
I got nauseated typing that though, because while(true) is a horrible idea. Better would be to track time in Update() and call Movement() every 5 seconds, like so:
private float timer = 0f;
void Update() {
timer += Time.deltaTime;
if (timer > 5f) {
Movement();
timer -= 5f;
}
}