简体   繁体   English

Unity-WaitForSeconds()不起作用

[英]Unity - WaitForSeconds() does not work

I am developing some flight simulator programme. 我正在开发一些飞行模拟器程序。 Right now I am trying to get the level to restart after a delay of 4 seconds, but instead it is waiting forever and not responding. 现在,我正在尝试让该级别在延迟4秒后重新启动,但是它一直在等待并且没有响应。 This is my code (in C#) right now: 这是我的代码(在C#中):

void Update () {

    //other irrelevant code in front

    float TerrainHeightLocation = Terrain.activeTerrain.SampleHeight (transform.position);

    if (TerrainHeightLocation > transform.position.y) { //the plane crashed

        StartCoroutine(Wait(TerrainHeightLocation));


    }
}

IEnumerator Wait( float TerrainHeightLocation) {
    transform.position = new Vector3 (transform.position.x,
                                      TerrainHeightLocation,
                                      transform.position.z);
    Instantiate(explosion, transform.position, transform.rotation);
    Destroy(gameObject);

    Debug.Log ("Waiting");
    yield return new WaitForSeconds(4.0f); // waits x seconds

    Debug.Log ("Waited for x seconds");

    Application.LoadLevel(Application.loadedLevel);
    Debug.Log ("Reloaded level");

}

It would be a great help if anyone could find a problem in the code, because I have been trying all day and I cannot fix it. 如果任何人都可以在代码中找到问题,那将是一个很大的帮助,因为我已经整天都在努力,而且无法修复它。

Thanks! 谢谢!

Typically when WaitForSeconds doesn't work it's one of two things: 通常,当WaitForSeconds无法正常工作时,它是以下两种情况之一:

  1. Time.timeScale is set to 0. Time.timeScale设置为0。
  2. The object is being destroyed or made inactive before the time is up. 在时间到之前,该对象已被破坏或变为非活动状态。

In your case you are destroying the very game object that runs the Coroutine before you call yield WaitForSeconds. 在您的情况下,您要在调用yield WaitForSeconds之前销毁运行协程的游戏对象。 Destroy is deferred until the end of the frame so the code up until the yield will execute, but then the GameObject & MonoBehaviour will be destroyed and the Coroutine along with it. 销毁被推迟到帧的末尾,这样代码才执行直到成品率,但是随后GameObject和MonoBehaviour将被销毁,协程也随之销毁。

Solution: use a Coroutine on an object that persists between the level ending and restarting. 解决方案:在关卡结束和重启之间持续存在的对象上使用协程。 To make an object persist even when a level is loaded (as you are doing in your code) you need to call DontDestroyOnLoad . 为了使对象即使在加载关卡时仍然持久(就像在代码中所做的那样),您需要调用DontDestroyOnLoad

The problem with your code is you are destroying the very gameobject from which this coroutine is called. 代码的问题在于,您正在销毁此协程所调用的游戏对象。 So when you call destroy on your game object that will stop running coroutine (at least that should be happening here). 因此,当您在游戏对象上调用destroy时,它将停止运行协程(至少应该在此处发生)。 The solution to this problem is instead of destroying the gameobject you can always disable its renderer and colliders. 解决此问题的方法是,始终可以禁用其渲染器和对撞机,而不是破坏游戏对象。 Then re enable them when your new level is loaded. 然后在加载新级别时重新启用它们。 So you will not need to destroy the object. 因此,您将不需要销毁对象。

In the case of your scene it looks like it has been predefined .If your scene has initialised objects from default then just hide the object which needs to be destroyed. 对于您的场景,它看起来像是预定义的。如果您的场景默认情况下具有初始化的对象,则只需隐藏需要销毁的对象即可。 I think that should solve your problem. 我认为应该可以解决您的问题。 The load level will destroy all the objects in scene and reload them. 负载级别将破坏场景中的所有对象并重新加载它们。

     IEnumerator Wait( float TerrainHeightLocation) {
        transform.position = new Vector3 (transform.position.x,
                                          TerrainHeightLocation,
                                          transform.position.z);
        Instantiate(explosion, transform.position, transform.rotation);
        //Hide the game object renderer and colliders here instead of destroying it
        //as this is the script which controls your coroutine execution.
        gameObject.renderer.enabled = false;
        gameObject.collider.enabled = false;

        //Make sure your game object has required renderer and collider or else the           
        //above code will give errors as it wont be able to find them

        Debug.Log ("Waiting");
        yield return new WaitForSeconds(4.0f); // waits x seconds

        Debug.Log ("Waited for x seconds");

        Application.LoadLevel(Application.loadedLevel);
        Debug.Log ("Reloaded level");

    }

Similer Question Similer问题

I still don't understand why would people still consider using co routine in a simple cases. 我仍然不明白为什么人们仍然会在简单的情况下考虑使用协例。 I would suggest only to use co routine as if you're checking something on server. 我建议仅使用协同例程,就好像您要检查服务器上的某些东西一样。 Making co routine calls with other functions. 与其他函数进行共同例程调用。

But please refrain from using co routine calls when you just want to "WAIT" <- that is the key word. 但是,当您只想“ WAIT” <-这是关键字时,请避免使用协同例程调用。 Wait not co routine on the function. 在函数上不要等待例程。

If your goal is to restart the game by using Application.Load then use this. 如果您的目标是使用Application.Load重新启动游戏,请使用它。

public void MyRestart(){

   Application.LoadLevel("MyLevel");
   // Put your codes where ever in this method.
}

Then just use Invoke Method 然后只需使用调用方法

Invoke ("MyRestart", 4);

//This will call MyRestart Function after 4 seconds. //这将在4秒钟后调用MyRestart函数。

bool isDead = false;

void Update () //Update calls your function every frame. So we should call IEnumerator for one time. I will use bool check for this.
{

    //other irrelevant code in front

    float TerrainHeightLocation = Terrain.activeTerrain.SampleHeight (transform.position);

    if ( (TerrainHeightLocation > transform.position.y) && !isDead ) { //the plane crashed

        isDead = true;
        InstantiateFunc( TerrainHeightLocation );
        StartCoroutine(Death);        


    }
}

void InstantiateFunc( float TerrainHeightLocation) {
    transform.position = new Vector3 (transform.position.x,
                                      TerrainHeightLocation,
                                      transform.position.z);
    Instantiate(explosion, transform.position, transform.rotation);
    Destroy(gameObject);

    Debug.Log ("Waiting");

}

IEnumerator Death{
yield return new WaitForSeconds(4.0f); // waits x seconds

        Debug.Log ("Waited for x seconds");

        Application.LoadLevel(Application.loadedLevel);
        Debug.Log ("Reloaded level");
}

I have not tested, I hope it works 我尚未测试,希望它能正常工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM