繁体   English   中英

C# 协程在 Unity 中不起作用

[英]C# Coroutine doesnt works in Unity

我正在尝试制作一个基本的平台游戏,但我的关卡控制器脚本不起作用,它需要先加载加载场景,然后再加载下一个关卡,但它会不断加载下一个关卡

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class LevelController : MonoBehaviour
{
    [SerializeField] string nextLevel;

    private Gem[] gems;

    void OnEnable()
    {
        gems = FindObjectsOfType<Gem>();    
    }

    IEnumerator Wait()
    {
        yield return new WaitForSeconds(3);
    }

    void Update()
    {
        if (ReadyToNextLevel())
        {
            SceneManager.LoadScene("Loading");
            StartCoroutine(Wait());
            SceneManager.LoadScene(nextLevel);
        }
    }

    bool ReadyToNextLevel()
    {
        foreach (var gem in gems)
        {
            if (gem.gameObject.activeSelf)
            {
                return false;
            }
        }
        return true;
    }

}

您的代码中有两个大问题。

  1. 启动协程延迟启动该程序的方法!

    如果您希望在协程完成后发生某些事情,您需要将其移动到例程本身中或使用回调。

  2. 然而,问题是:您正在加载一个新场景,即“加载”场景 -> 当前场景已卸载 -> 该脚本所在的对象被销毁 -> 例程将不再执行。

    除了您的对象是DontDestroyOnLoad从您的代码看来并非如此。


因此,为了解决这两个问题,您需要确保在加载另一个场景时不会破坏此对象,至少在完成加载过程之前不会。

你可以这样做,例如

public class LevelController : MonoBehaviour
{
    [SerializeField] string nextLevel;

    private Gem[] gems;

    void OnEnable()
    {
        gems = FindObjectsOfType<Gem>();    

        // Makes sure this is not destroyed when another scene is load
        DontDestroyOnLoad(gameObject);
    }

    bool alreadyLoading;

    IEnumerator Wait(Action whenDone)
    {
        yield return new WaitForSeconds(3);

        // invoke the callback action
        whenDone?.Invoke();
    }

    void Update()
    {
        if (ReadyToNextLevel() && ! alreadyLoading)
        {
            alreadyLoading = true;
            SceneManager.LoadScene("Loading");
            StartCoroutine(Wait(() =>
            {
                // This will be done after the routine finished
                SceneManager.LoadScene(nextLevel);

                // Now we don't need this object anymore
                Destroy(gameObject);
            }));
        }
    }

    bool ReadyToNextLevel()
    {
        foreach (var gem in gems)
        {
            if (gem.gameObject.activeSelf)
            {
                return false;
            }
        }
        return true;
    }
}

编辑:请参阅 derHugo 的回答。 他们比我更熟悉 Unity,并指出您的脚本将在场景更改时卸载。

您的Wait()协程立即产生,因此StartCoroutine(Wait())将立即返回并加载下一个场景。

如果你想在加载之前等待三秒钟,那么将加载放在协程中。

像这样:

private bool isLoading;

void Update()
{
    if (!isLoading && ReadyToNextLevel())
        StartCoroutine(LoadNextLevel());
}

IEnumerator LoadNextLevel()
{
    isLoading = true;
    SceneManager.LoadScene("Loading");
    yield return new WaitForSeconds(3);
    SceneManager.LoadScene(nextLevel);    
    isLoading = false;   
}

有关更多详细信息,请参阅协程帮助

这不起作用有两个原因,首先当您加载到加载场景中时,游戏对象被销毁,因为您还没有告诉它DontDestroyOnLoad ,因此脚本将从当前场景中“删除”。 其次,当你调用协程时,它会调用协程,然后立即继续下一行代码,它不会等待协程完成才继续。 我认为 derHugo 涵盖了如何解决这些问题。

暂无
暂无

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

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