Как сделать script ожидание/сон простым способом в единстве

Как установить между 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);

Я уже пробовал разные вещи, но не работал, вот так:

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

В bash будет:

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

но я не могу понять, как я делаю это в Unity с С#

Ответ 1

Есть много способов подождать в Unity. Это действительно просто, но я думаю, что стоит обратить внимание на большинство способов сделать это:

1. С сопрограммой и WaitForSeconds.

Это, безусловно, самый простой способ. Поместите весь код, который вам нужно подождать некоторое время в функции сопрограммы, вы можете подождать с WaitForSeconds. Обратите внимание, что в функции coroutine вы вызываете функцию с помощью StartCoroutine(yourFunction).

Пример ниже повернется на 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. С сопрограммой и WaitForSecondsRealtime.

Единственное различие между 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);
}

Подождите и вы сможете увидеть, сколько времени вы ждали:

3. С сопрограммой и приращением переменной каждый кадр с Time.deltaTime.

Хорошим примером этого является то, когда вам нужно, чтобы таймер отображал на экране сколько времени он ждал. В принципе, как таймер.

Также хорошо, когда вы хотите прервать wait/sleep с переменной boolean, когда она истинна. Здесь можно использовать yield break;.

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

Вы можете упростить это, перемещая цикл 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;
    }
}

Подождите/спящий режим, пока переменная не изменится или не будет равна другому значению:

4. С сопрограммой и функцией WaitUntil:

Подождите, пока условие не станет true. Например, функция, ожидающая, что оценка игрока будет 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. С сопрограммой и функцией WaitWhile.

Подождите, пока условие true. Например, когда вы хотите выйти из приложения, когда нажата клавиша эвакуации.

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. С помощью функции Invoke:

Вы можете позвонить в Unity для вызова функции в будущем. Когда вы вызываете функцию Invoke, вы можете передать время ожидания до вызова этой функции во второй параметр. Пример ниже вызовет функцию feedDog() после 5 секунд, на который вызывается Invoke.

void Start()
{
    Invoke("feedDog", 5);
    Debug.Log("Will feed dog after 5 seconds");
}

void feedDog()
{
    Debug.Log("Now feeding Dog");
}

7. С помощью функции Update() и Time.deltaTime.

Это просто как # 3, за исключением того, что он не использует сопрограмму. Он использует функцию Update.

Проблема заключается в том, что для этого требуется так много переменных, чтобы он не запускался каждый раз, а только один раз, когда таймер закончился после ожидания.

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

Есть еще другие способы подождать в Unity, но вы должны обязательно знать те, о которых говорилось выше, поскольку это облегчает создание игр в Unity. Когда использовать каждый из них зависит от обстоятельств.

Для вашей конкретной проблемы это решение:

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

И для вызова/запуска функции сопрограммы с вашего запуска или функции обновления вы вызываете ее с помощью

StartCoroutine (showTextFuntion());

Ответ 2

Вы были правы использовать 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

В .Net 4.x вы можете использовать Task-based Asynchronous Pattern (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.");
    }
}

это функция для использования .Net 4.x с Unity, пожалуйста, смотрите эту ссылку для описания о ней

и эту ссылку для примера проекта и сравнить его с сопрограммой

Но поскольку документация говорит, что это не полная замена на сопрограмму