using System.Collections; using UnityEngine; using UnityEngine.UI; using TMPro; using BaseGames.Core.Events; using BaseGames.Localization; namespace BaseGames.UI { /// /// 全屏加载界面:进度条 + 提示文字 + 随机背景图(架构 10_UIModule §7.7)。 /// public class LoadingScreenManager : MonoBehaviour { [SerializeField] private GameObject _loadingRoot; [SerializeField] private Image _progressFill; [SerializeField] private TMP_Text _tipText; [SerializeField] private Image[] _backgroundArts; [SerializeField] private string[] _tipMessages; // 本地化 key(对应 "UI" 表中的条目,如 "tip_explore") [SerializeField] private float _minDisplayTime = 0.5f; [Header("Event Channels")] [SerializeField] private VoidEventChannelSO _onLoadingStarted; [SerializeField] private VoidEventChannelSO _onLoadingComplete; [SerializeField] private FloatEventChannelSO _onLoadingProgressUpdated; private float _shownAt; private readonly CompositeDisposable _subs = new(); private void OnEnable() { _onLoadingStarted?.Subscribe(Show).AddTo(_subs); _onLoadingComplete?.Subscribe(Hide).AddTo(_subs); _onLoadingProgressUpdated?.Subscribe(SetProgress).AddTo(_subs); } private void OnDisable() { _subs.Clear(); } // ── 公开 API(SceneLoader 可直接调用)──────────────────────────────── public void Show() { _shownAt = Time.unscaledTime; if (_loadingRoot != null) _loadingRoot.SetActive(true); if (_progressFill != null) _progressFill.fillAmount = 0f; // 随机背景 if (_backgroundArts != null && _backgroundArts.Length > 0) { foreach (var bg in _backgroundArts) if (bg != null) bg.enabled = false; _backgroundArts[Random.Range(0, _backgroundArts.Length)].enabled = true; } // 随机提示(通过 LocalizationManager 解析 key) if (_tipText != null && _tipMessages != null && _tipMessages.Length > 0) _tipText.text = LocalizationManager.Get(_tipMessages[Random.Range(0, _tipMessages.Length)], LocalizationTable.UI); } public void Hide() => StartCoroutine(HideAfterMinTime()); public void SetProgress(float value) { if (_progressFill != null) _progressFill.fillAmount = Mathf.Clamp01(value); } // ── 内部 ───────────────────────────────────────────────────────────── // 缓存等待对象以避免典型路径(剩余时间 == _minDisplayTime)下的重复分配。 private WaitForSecondsRealtime _cachedFullWait; private IEnumerator HideAfterMinTime() { float elapsed = Time.unscaledTime - _shownAt; float remaining = _minDisplayTime - elapsed; if (remaining > 0f) { // 完整剩余 ≈ 显示时间时复用缓存对象;否则按需新建(罕见路径)。 if (Mathf.Approximately(remaining, _minDisplayTime)) { _cachedFullWait ??= new WaitForSecondsRealtime(_minDisplayTime); yield return _cachedFullWait; } else { yield return new WaitForSecondsRealtime(remaining); } } if (_loadingRoot != null) _loadingRoot.SetActive(false); } } }