首页 > 解决方案 > C# 协程在 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;
    }

}

标签: c#unity3dcoroutine

解决方案


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

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

推荐阅读