Unity - WaitForSeconds()不起作用

时间:2015-04-10 02:16:01

标签: c# unity3d

我正在开发一些飞行模拟器程序。现在我试图在4秒的延迟后让级别重新启动,但它正在等待永远而没有响应。这是我的代码(在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");

}

如果有人能在代码中发现问题,那将是一个很大的帮助,因为我一整天都在努力,我无法解决它。

谢谢!

4 个答案:

答案 0 :(得分:4)

通常,当WaitForSeconds不起作用时,它是两件事之一:

  1. Time.timeScale设置为0.
  2. 对象在时间结束前被销毁或处于非活动状态。
  3. 在你的情况下,在调用yield WaitForSeconds之前,你正在销毁运行Coroutine的游戏对象。 Destroy被推迟到帧结束,所以代码一直到yield将执行,然后GameObject& MonoBehaviour将被摧毁,Coroutine也将被摧毁。

    解决方案:对在结束和重新启动之间持续存在的对象使用Coroutine。要使对象在加载关卡时保持不变(正如您在代码中所做的那样),您需要调用DontDestroyOnLoad

答案 1 :(得分:2)

你的代码的问题是你正在破坏调用这个协程的游戏对象。所以当你在游戏对象上调用destroy时会停止运行协同程序(至少应该在这里发生)。这个问题的解决方案不是破坏游戏对象,而是可以随时禁用其渲染器和对撞机。然后在加载新级别时重新启用它们。所以你不需要销毁这个对象。

对于你的场景,它看起来已被预定义。如果你的场景已经默认初始化了对象,那么只需隐藏需要销毁的对象。我认为这应该可以解决你的问题。负载级别将销毁场景中的所有对象并重新加载它们。

     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

答案 2 :(得分:2)

我仍然不明白为什么人们仍然会考虑在简单的情况下使用co例程。我建议只使用co例程,就好像你在服务器上检查一些东西一样。与其他函数进行常规调用。

但是当你只想“等待”< - 这是关键词时,请不要使用常规通话。等待该功能不合作。

如果您的目标是使用Application.Load重新启动游戏,请使用此功能。

public void MyRestart(){

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

然后只使用Invoke Method

Invoke ("MyRestart", 4);

//这将在4秒后调用MyRestart函数。

答案 3 :(得分:0)

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

我没有测试过,我希望它有效