[Unity] 如果发现异步加载结果没有显示或者表现为没有异步性,可以检查自己的结果是否被遮挡了

332 阅读2分钟

情景

我的情景是,在 StartUI 中控制进度条更新,在 StartGameController 中控制进度条的目标,在 AppController 中设置进度条的目标

StartGameController 看上去与 AppController 的功能重合,是因为 AppController 可能还管理着 HomeController, GameController 之类的脚本。AppController 是负责协调这些 Controller 之间的顺序的

现在的问题是,我在 AppController 中使用协程等待 StartUI 中的 Tween 的 WaitForCompletion 失败了,协程在我 yield return XXX.WaitForCompletion(); 这一步直接通过了,但是 Tween 本身还没有结束

AppController.cs

StartGameController.Instance.SetProgress(100);

yield return new WaitForEndOfFrame();

Debug.Log(StartGameController.Instance.startUI.ProgressTween.IsComplete());

yield return StartGameController.Instance.startUI.ProgressTween.WaitForCompletion();

打印出来是 False

StartGameController.cs

using System.Collections;
using DG.Tweening;
using UnityEngine;
using Universal;

public class StartGameController : Singleton<StartGameController>
{
    [SerializeField]
    public StartUI startUI;

    public void SetProgress(int progress)
    {
        startUI.Progress = progress;
    }
}

StartUI.cs

using System;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class StartUI : MonoBehaviour
{
    [SerializeField]
    private GameObject panel;

    public GameObject Panel => panel;

    [SerializeField]
    private Slider slider;

    [SerializeField]
    private Text sliderText;

    private int progress = 0;

    public int Progress
    {
        get => progress;
        set
        {
            int target = value;
            progressTween?.Pause();
            progressTween = DOTween.To(() => progress, value => progress = value, target, 0.5f);
            progressTween.Play();

            Debug.Log(progressTween.IsComplete());
        }
    }

    private Tween progressTween;

    public Tween ProgressTween => progressTween;

    private void Update()
    {
        sliderText.text = string.Format("{0}%", progress);
        slider.value = (float)progress / 100f;
    }
}

假设我改成 AppController 会启动 StartUI 中的协程

AppController.cs

yield return StartCoroutine(StartGameController.Instance.SetProgress(100));

StartUI.cs

using System.Collections;
using DG.Tweening;
using UnityEngine;
using Universal;

public class StartGameController : Singleton<StartGameController>
{
    [SerializeField]
    public StartUI startUI;

    public IEnumerator SetProgress(int progress)
    {
        startUI.Progress = progress;

        yield return startUI.ProgressTween.WaitForCompletion();
    }
}

结果仍然是 AppController 中直接通过了进度条的等待协程

假如我再把所有的都拆开,在 AppController 中创建和等待 Tween

AppController.cs

Tween progressTween = DOTween.To(() => StartGameController.Instance.Process, 
    value => StartGameController.Instance.Process = value, 100, 0.5f);
progressTween.Play();

yield return new WaitForSeconds(1f);

yield return progressTween.WaitForCompletion();

Debug.Log(progressTween == null);

Debug.Log(progressTween.IsComplete());

StartUI.cs

using System.Collections;
using DG.Tweening;
using UnityEngine;
using Universal;

public class StartGameController : Singleton<StartGameController>
{
    [SerializeField]
    private StartUI startUI;

    public int Process
    {
        get => startUI.Progress;
        set
        {
            startUI.Progress = value;
        }
    }
}

结果也还是没有等待

原因

其实我上面写的都没有错

只是我的异步表现是一个进度条在移动

但是我唤醒进度条移动之后又加载了一个新场景 Additive 方式的

这个新场景的 UI 直接把我的旧场景的 UI 给覆盖掉了,所以我看不到旧场景的 UI 的进度条的情况

这就给我一种错觉是,好像旧场景的 UI 进度条瞬间加载完了一样,实际上不是

所以说如果发现异步加载结果没有显示或者表现为没有异步性,可以检查自己的结果是否被遮挡了