using DG.Tweening; using Event; using UnityEngine; using UnityEngine.UI; using UnityGameFramework.Runtime; namespace UI { public class BgForm : UGuiForm { [SerializeField] private Image _bgImage; [SerializeField] private Image _fadeMaskImage; [SerializeField] private float _fadeToBlackDuration = 0.2f; [SerializeField] private float _fadeFromBlackDuration = 0.25f; [SerializeField] private Ease _fadeEase = Ease.Linear; private Sprite _currentSprite; private string _currentAssetName = string.Empty; private Tween _fadeTween; private int _refreshVersion; protected override void OnOpen(object userData) { base.OnOpen(userData); if (!(userData is BgFormContext context)) { Log.Error("BgFormContext is invalid."); return; } RefreshUI(context); } protected override void OnClose(bool isShutdown, object userData) { _refreshVersion++; KillFadeTween(); SetFadeMaskAlpha(0f); _currentSprite = null; _currentAssetName = string.Empty; if (_bgImage != null) { _bgImage.sprite = null; } base.OnClose(isShutdown, userData); } public void RefreshUI(BgFormContext context) { if (context == null) { Log.Warning("BgForm refresh failed. context is null."); return; } int requestId = context.TransitionRequestId; bool shouldFadeTransition = _currentSprite != null; if (context.Sprite != null) { RefreshWithSprite(context.Sprite, context.BackgroundAssetName, requestId); return; } string targetAssetName = string.IsNullOrWhiteSpace(context.BackgroundAssetName) ? string.Empty : context.BackgroundAssetName.Trim(); if (string.IsNullOrEmpty(targetAssetName)) { PublishTransitionCompleted(requestId); return; } if (_currentSprite != null && string.Equals(_currentAssetName, targetAssetName)) { PublishTransitionCompleted(requestId); return; } if (GameEntry.SpriteCache == null) { Log.Warning("BgForm refresh failed. SpriteCache is missing."); PublishTransitionCompleted(requestId); return; } int version = ++_refreshVersion; TweenCallback loadAndApplySprite = () => { if (version != _refreshVersion) { return; } GameEntry.SpriteCache.GetSprite(targetAssetName, sprite => { if (version != _refreshVersion) { return; } if (sprite != null) { _currentSprite = sprite; _currentAssetName = targetAssetName; if (_bgImage != null) { _bgImage.sprite = sprite; } } else { Log.Warning("BgForm refresh failed. Can not load sprite '{0}'.", targetAssetName); } if (shouldFadeTransition) { FadeFromBlack(() => { PublishTransitionCompleted(requestId); }); } else { PublishTransitionCompleted(requestId); } }); }; if (shouldFadeTransition) { FadeToBlack(loadAndApplySprite); } else { loadAndApplySprite.Invoke(); } } private void RefreshWithSprite(Sprite sprite, string backgroundAssetName, int requestId) { if (sprite == null) { PublishTransitionCompleted(requestId); return; } bool isSameSprite = _currentSprite == sprite; bool hasSameAssetName = !string.IsNullOrEmpty(backgroundAssetName) && string.Equals(_currentAssetName, backgroundAssetName); if (isSameSprite && (string.IsNullOrEmpty(backgroundAssetName) || hasSameAssetName)) { PublishTransitionCompleted(requestId); return; } bool shouldFadeTransition = _currentSprite != null; int version = ++_refreshVersion; TweenCallback applySprite = () => { if (version != _refreshVersion) { return; } _currentSprite = sprite; _currentAssetName = string.IsNullOrWhiteSpace(backgroundAssetName) ? _currentAssetName : backgroundAssetName.Trim(); if (_bgImage != null) { _bgImage.sprite = sprite; } if (shouldFadeTransition) { FadeFromBlack(() => { PublishTransitionCompleted(requestId); }); } else { PublishTransitionCompleted(requestId); } }; if (shouldFadeTransition) { FadeToBlack(applySprite); } else { applySprite.Invoke(); } } private void FadeToBlack(TweenCallback onComplete) { EnsureFadeMask(); if (_fadeMaskImage == null) { onComplete?.Invoke(); return; } _fadeMaskImage.transform.SetAsLastSibling(); KillFadeTween(); if (_fadeToBlackDuration <= 0f) { SetFadeMaskAlpha(1f); onComplete?.Invoke(); return; } _fadeTween = _fadeMaskImage.DOFade(1f, _fadeToBlackDuration) .SetEase(_fadeEase) .OnComplete(onComplete); } private void FadeFromBlack(TweenCallback onComplete = null) { EnsureFadeMask(); if (_fadeMaskImage == null) { onComplete?.Invoke(); return; } _fadeMaskImage.transform.SetAsLastSibling(); KillFadeTween(); if (_fadeFromBlackDuration <= 0f) { SetFadeMaskAlpha(0f); onComplete?.Invoke(); return; } _fadeTween = _fadeMaskImage.DOFade(0f, _fadeFromBlackDuration) .SetEase(_fadeEase) .OnComplete(onComplete); } private void EnsureFadeMask() { if (_fadeMaskImage != null) { return; } RectTransform parentRect = transform as RectTransform; if (parentRect == null) { return; } GameObject maskObject = new GameObject("BgFadeMask", typeof(RectTransform), typeof(Image)); maskObject.transform.SetParent(parentRect, false); RectTransform maskRect = maskObject.GetComponent(); if (maskRect != null) { maskRect.anchorMin = Vector2.zero; maskRect.anchorMax = Vector2.one; maskRect.offsetMin = Vector2.zero; maskRect.offsetMax = Vector2.zero; } _fadeMaskImage = maskObject.GetComponent(); if (_fadeMaskImage != null) { _fadeMaskImage.raycastTarget = false; _fadeMaskImage.color = Color.clear; } } private void KillFadeTween() { if (_fadeTween == null) { return; } _fadeTween.Kill(); _fadeTween = null; } private void SetFadeMaskAlpha(float alpha) { if (_fadeMaskImage == null) { return; } Color color = _fadeMaskImage.color; color.r = 0f; color.g = 0f; color.b = 0f; color.a = Mathf.Clamp01(alpha); _fadeMaskImage.color = color; } private void PublishTransitionCompleted(int requestId) { if (requestId <= 0) { return; } GameEntry.Event.Fire(this, BgTransitionCompletedEventArgs.Create(requestId)); } } }