如何使脚本以统一的简单方式等待/睡眠

时间:2021-02-22 21:32:43

How can put between the TextUI.text = .... a sleep function, for wait 3 seconds between each phrase?

如何在TextUI.text = ....之间放置一个睡眠功能,在每个短语之间等待3秒?

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 didn't worked, such 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 would be:

在bash中将是:

echo "Welcome to Number Wizard!"
sleep 3
echo "The highest number you can pick is 1000"
sleep 3
.....

but I can't figured out how i do this in Unity with C#

但我无法弄清楚我是如何在Unity中用C#做的

3 个解决方案

#1


There are many ways to wait in Unity. It is really simple but I think it's worth covering most ways to do these:

在Unity中有很多方法可以等待。这很简单,但我认为值得涵盖大多数方法来做到这些:

1.With a coroutine and WaitForSeconds.

1.具有协程和WaitForSeconds。

The 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).

这是迄今为止最简单的方法。在协程函数中放置所需的所有代码等待一段时间,然后等待WaitForSeconds。请注意,在coroutine函数中,使用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.

下面的例子将旋转90度,等待4秒,旋转40度并等待2秒,然后最后旋转20度。

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.

2.具有协程和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.

WaitForSeconds和WaitForSecondsRealtime之间的唯一区别是WaitForSecondsRealtime正在使用未缩放的等待时间,这意味着当使用Time.timeScale暂停游戏时,WaitForSecondsRealtime函数不会受到影响,但WaitForSeconds会受到影响。

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.

3.使用协程并使用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.

你仍然可以通过将while循环移动到另一个协程函数并产生它来简化它,并且仍然可以看到它计数甚至中断计数器。

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:

4.使用协同程序和WaitUntil函数:

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.

等到条件成立。一个例子是等待玩家得分为100然后加载下一级别的功能。

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 Leve");

    //Increment and Load next scene
    nextScene++;
    SceneManager.LoadScene(nextScene);
}

5.With a coroutine and the WaitWhile function.

5.具有协程和WaitWhile功能。

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:

6.使用Invoke功能:

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.

你可以打电话告诉Unity将来调用函数。当您调用Invoke函数时,您可以在将该函数调用到其第二个参数之前传递等待时间。下面的示例将在调用Invoke 5秒后调用feedDog()函数。

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.

7.使用Update()函数和Time.deltaTime。

It's just like #3 except that it does not use coroutine. It uses the Update function.

就像#3一样,它不使用协程。它使用Update功能。

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.

还有其他方法可以在Unity中等待,但你应该清楚地知道上面提到的那些,这样可以更容易地在Unity中制作游戏。何时使用每一个取决于具体情况。

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());

#2


You were correct to use WaitForSeconds. But I suspect that you tried using it without coroutines. That's how it should work:

你使用WaitForSeconds是正确的。但我怀疑你尝试使用它没有协同程序。它应该如何工作:

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);
}

#3


With .Net 4.x you can use Task-based Asynchronous Pattern (TAP) to achieve this:

使用.Net 4.x,您可以使用基于任务的异步模式(TAP)来实现此目的:

// .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

这是使用.Net 4.x与Unity的功能,请参阅此链接以获取有关它的说明

and this link for sample project and compare it with coroutine

和示例项目的这个链接,并与协程进行比较

But becareful as documentation says that This is not fully replacement with coroutine

但是,因为文档说这并不完全取代协程

#1


There are many ways to wait in Unity. It is really simple but I think it's worth covering most ways to do these:

在Unity中有很多方法可以等待。这很简单,但我认为值得涵盖大多数方法来做到这些:

1.With a coroutine and WaitForSeconds.

1.具有协程和WaitForSeconds。

The 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).

这是迄今为止最简单的方法。在协程函数中放置所需的所有代码等待一段时间,然后等待WaitForSeconds。请注意,在coroutine函数中,使用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.

下面的例子将旋转90度,等待4秒,旋转40度并等待2秒,然后最后旋转20度。

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.

2.具有协程和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.

WaitForSeconds和WaitForSecondsRealtime之间的唯一区别是WaitForSecondsRealtime正在使用未缩放的等待时间,这意味着当使用Time.timeScale暂停游戏时,WaitForSecondsRealtime函数不会受到影响,但WaitForSeconds会受到影响。

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.

3.使用协程并使用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.

你仍然可以通过将while循环移动到另一个协程函数并产生它来简化它,并且仍然可以看到它计数甚至中断计数器。

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:

4.使用协同程序和WaitUntil函数:

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.

等到条件成立。一个例子是等待玩家得分为100然后加载下一级别的功能。

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 Leve");

    //Increment and Load next scene
    nextScene++;
    SceneManager.LoadScene(nextScene);
}

5.With a coroutine and the WaitWhile function.

5.具有协程和WaitWhile功能。

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:

6.使用Invoke功能:

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.

你可以打电话告诉Unity将来调用函数。当您调用Invoke函数时,您可以在将该函数调用到其第二个参数之前传递等待时间。下面的示例将在调用Invoke 5秒后调用feedDog()函数。

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.

7.使用Update()函数和Time.deltaTime。

It's just like #3 except that it does not use coroutine. It uses the Update function.

就像#3一样,它不使用协程。它使用Update功能。

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.

还有其他方法可以在Unity中等待,但你应该清楚地知道上面提到的那些,这样可以更容易地在Unity中制作游戏。何时使用每一个取决于具体情况。

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());

#2


You were correct to use WaitForSeconds. But I suspect that you tried using it without coroutines. That's how it should work:

你使用WaitForSeconds是正确的。但我怀疑你尝试使用它没有协同程序。它应该如何工作:

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);
}

#3


With .Net 4.x you can use Task-based Asynchronous Pattern (TAP) to achieve this:

使用.Net 4.x,您可以使用基于任务的异步模式(TAP)来实现此目的:

// .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

这是使用.Net 4.x与Unity的功能,请参阅此链接以获取有关它的说明

and this link for sample project and compare it with coroutine

和示例项目的这个链接,并与协程进行比较

But becareful as documentation says that This is not fully replacement with coroutine

但是,因为文档说这并不完全取代协程