Как исправить баг повторной асинхронной загрузки сцены?

У меня есть сцена StartScene с кнопкой "Новая игра". По нажатию на эту кнопку запускается "промежуточная" сцена загрузки LoadingScene.
//  Клик по кнопке "Новая игра" на сцене StartScene .
SceneManager.LoadScene("LoadingScene");


LoadingScene, используя корутину, выводит прогресс загрузки и загружает сцену Scene1.
AsyncOperation asyncOperation;
public Image loadingBarFill;
public Text loadingText;
private string sceneName="Scene1";

void Start()
{
    StartCoroutine(LoadSceneCoroutine());
}



IEnumerator LoadSceneCoroutine()
{
    yield return new WaitForSeconds(1f);
    asyncOperation = SceneManager.LoadSceneAsync(sceneName);
    while(!asyncOperation.isDone)
    {           
        float progress = asyncOperation.progress/0.9f;
        loadingBarFill.fillAmount = progress;
        loadingText.text = "Загрузка"+string.Format("{0:0}%", progress*100f);
        yield return 0;
        
    }
    
}


Самая обычная загрузка уровня через промежуточную сцену.

В первый раз всё работает. StartScene -> LoadingScene -> Scene1. Всё хорошо - Scene1 загружена.
Далее на Scene1 я нажимаю на кнопку - "Вернуться в главное меню игры" и перехожу к сцене StartScene.
//  Клик по кнопке "Вернуться в главное меню игры" на сцене Scene1.
SceneManager.LoadScene("StartScene ");


И снова повторяю действия. Нажимаю кнопку "Новая игра" - перехожу на сцену LoadingScene и ничего не происходит. Прогресс бар стоит на нуле, сцена Scene1 не загружается.

Без асинхронной загрузки, простыми SceneManager.LoadScene всё загружается.
Я знаю, что при асинхронной загрузке, надо выгружать сцену. Пробовал разные варианты выгрузки - не помогало.
Как исправить баг повторной асинхронной загрузки сцены?
  • Вопрос задан
  • 241 просмотр
Решения вопроса 1
logpol32
@logpol32 Автор вопроса
Вот правильный ответ.
Оказывается, правильный код есть в мануале Unity.
Но, почти во всех видео на ютубе, показан неверный код, с багом повторной загрузки.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;


public class LoadingSceneScript : MonoBehaviour
{

    [SerializeField] private Image loadingBarFillObject;
    [SerializeField] private Text loadingTextObject;
    private string sceneName = "Scene1"; // Имя сцены для загрузки.
    private string loadingText = "Loading...";  // Надпись при загрузке.
    float progress;

    void Start()
    {
        loadingTextObject.text = loadingText +" 0%";
        DataHolder.ReadAllLocalizationData(() =>
        {
        StartCoroutine(LoadSceneCoroutine());
        });
    }


    IEnumerator LoadSceneCoroutine()
    {
        yield return null;

        //Begin to load the Scene you specify
        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName);
        //Don't let the Scene activate until you allow it to
        asyncOperation.allowSceneActivation = false;

 
        while (!asyncOperation.isDone)
        {
            //Output the current progress
            progress = asyncOperation.progress / 0.9f;
            loadingBarFillObject.fillAmount = progress;
            loadingTextObject.text = loadingText + string.Format(" {0:0}%", progress * 100f);
    

            // Check if the load has finished
            if (asyncOperation.progress >= 0.9f)
            {    
                    asyncOperation.allowSceneActivation = true;
            }

            yield return null;
        }
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@Ente
Unity developer
Можно на стартовой сцене создать скрипт менеджер, который будет управлять асинхронными загрузками и выгрузками сцен. Основной смысл в том, чтобы асинхронная загрузка ждала асинхронной выгрузки всех сцен.

Создается два листа, scenesToLoad и scenesToUnload. Далее подписываемся на события SceneManager.sceneLoaded
SceneManager.sceneUnloaded, чтобы понимаеть, что у нас загрузилось и выгрузилась. Когда мы хотим загрузить сцену, мы помещаем ее имя в scenesToLoad (когда выгрузить - в scenesToUnload) и не загружаем ее асинхронно до тех пор, пока все асинхронные сцены не будут выгружены (scenesToUnload содержит хоть что-то). Как только лист scenesToUnload опустеет - грузим асинхронно все сцены, которые находятся в листе sceneToLoad.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы