如何在unity中简单的制作脚本wait/sleep

How to make the script wait/sleep in a simple way in unity

如何在 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);

我已经尝试了各种方法,但 none 都奏效了,例如:

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

但我不知道如何使用 C# 在 Unity 中执行此操作

您使用 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);
}

Unity中有多种等待方式。它们真的很简单,但我认为值得涵盖大多数方法:

1.有协程和WaitForSeconds.

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

WaitForSecondsWaitForSecondsRealtime 之间的唯一区别是 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.

递增一个变量

一个很好的例子就是当您需要计时器在屏幕上显示它已经等待了多长时间。基本上就像一个计时器。

当你想用一个 boolean 变量打断 wait/sleep 时,它也很好。这是可以使用 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;
    }
}

Wait/Sleep 直到变量改变或等于另一个值:

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

    //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 函数时,您可以将调用该函数之前的等待时间传递给它的第二个参数。下面的示例将在 5 秒后调用 feedDog() 函数 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);
}

然后 call/start 从你的 start 或 Update 函数调用协程函数,你用

调用它
StartCoroutine (showTextFuntion());

对于 .Net 4.x,您可以使用 Task-based 异步模式 (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 一起使用的功能,请参阅 this link for description about it

this link for sample project and compare it with coroutine

但是要小心,因为文档说 这不能完全替换为协程

这里有一个没有 StartCoroutine 的更简单的方法:

float t = 0f;
float waittime = 1f;

和内部 Update/FixedUpdate:

if (t < 0){
    t += Time.deltaTIme / waittime;
    yield return t;
}

使用异步和等待

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

//这是我在 Unity 中等待的一些代码的示例,我使用一个值进行了更新,并在每次更新时更新它,一旦它是值,if 语句正在寻找它 运行任务。

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