using System; using System.Collections; using AibisDream.Framework; using AibisDream.Kit; using AibisDream.SaveSystem; using AibisDream.Utility; using DG.Tweening; using UnityEngine; using UnityEngine.ResourceManagement.AsyncOperations; namespace AibisDream { /// /// 梦境场景通用图片展示器。只负责普通小图、大图与背景遮罩; /// 场景专属动态表现通过 与本组件解耦。 /// public class SpriteShowcase : Singleton { private const string DreamSpritePath = "Sprite/梦境/{0}.png"; [SerializeField] private SpriteRenderer _spriteRenderer; [SerializeField] private SpriteRenderer _backgroundSpriteRenderer; [SerializeField] private SpriteRenderer _largeSpriteRenderer; private string _currentSmallPicName; private string _currentLargePicName; public event Action PresentationChanging; private bool IsSmallShowing => _spriteRenderer != null && _spriteRenderer.gameObject.activeSelf; private bool IsLargeShowing => _largeSpriteRenderer != null && _largeSpriteRenderer.gameObject.activeSelf; public override void OnSingletonInit() { ClearSmallImmediate(); ClearLargeImmediate(); } private void OnDisable() { ClearSmallImmediate(); ClearLargeImmediate(); } private static string NormalizeDreamPicName(string picName) { if (string.IsNullOrEmpty(picName)) return picName; return picName.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ? picName.Substring(0, picName.Length - 4) : picName; } private IEnumerator LoadDreamSpriteInto( SpriteRenderer target, string picName, Action completed = null, Action warning = null) { if (target == null) { completed?.Invoke(false); yield break; } var key = string.Format(DreamSpritePath, NormalizeDreamPicName(picName)); var handle = ResourceSystem.LoadAsync(key); yield return handle; if (handle.Status == AsyncOperationStatus.Succeeded && handle.Result != null) { target.sprite = handle.Result; completed?.Invoke(true); } else { var message = $"[SpriteShowcase] Failed to load sprite: {key}"; Debug.LogError(message, this); warning?.Invoke(message); completed?.Invoke(false); } } public IEnumerator ShowObj(string picName, float duration = 1f) { NotifyPresentationChanging(); if (IsLargeShowing) yield return HideLargeInternal(duration); if (_spriteRenderer == null) yield break; _spriteRenderer.DOKill(); _spriteRenderer.gameObject.SetActive(true); var loaded = false; yield return LoadDreamSpriteInto(_spriteRenderer, picName, value => loaded = value); if (!loaded) { ClearSmallImmediate(); yield break; } _currentSmallPicName = NormalizeDreamPicName(picName); if (duration <= 0f) _spriteRenderer.SetAlpha(1f); else yield return _spriteRenderer.DOFade(1f, duration).WaitForCompletion(); } public IEnumerator ShowLargeObj(string picName, float duration = 1f) { NotifyPresentationChanging(); if (IsSmallShowing) yield return HideSmallInternal(0f); if (_largeSpriteRenderer == null) yield break; _largeSpriteRenderer.DOKill(); _largeSpriteRenderer.gameObject.SetActive(true); _largeSpriteRenderer.SetAlpha(0f); var loaded = false; yield return LoadDreamSpriteInto(_largeSpriteRenderer, picName, value => loaded = value); if (!loaded) { ClearLargeImmediate(); yield break; } _currentLargePicName = NormalizeDreamPicName(picName); if (duration <= 0f) _largeSpriteRenderer.SetAlpha(1f); else yield return _largeSpriteRenderer.DOFade(1f, duration).WaitForCompletion(); } public IEnumerator HideObj(float duration = 1f) { yield return HideObj(false, duration); } public IEnumerator HideObj(bool force, float duration = 1f) { NotifyPresentationChanging(); if (!force && !IsSmallShowing) yield break; yield return HideSmallInternal(duration); } public IEnumerator HideLargeObj(float duration = 1f) { NotifyPresentationChanging(); if (!IsLargeShowing) yield break; yield return HideLargeInternal(duration); } public IEnumerator HideAll(float duration = 1f) { NotifyPresentationChanging(); if (IsSmallShowing) yield return HideSmallInternal(duration); if (IsLargeShowing) yield return HideLargeInternal(duration); } private IEnumerator HideSmallInternal(float duration) { if (_spriteRenderer == null) yield break; _spriteRenderer.DOKill(); if (duration > 0f) yield return _spriteRenderer.DOFade(0f, duration).WaitForCompletion(); ClearSmallImmediate(); } private IEnumerator HideLargeInternal(float duration) { if (_largeSpriteRenderer == null) yield break; _largeSpriteRenderer.DOKill(); if (duration > 0f) yield return _largeSpriteRenderer.DOFade(0f, duration).WaitForCompletion(); ClearLargeImmediate(); } public IEnumerator FadeInAsync(float duration = 1f) { if (_backgroundSpriteRenderer == null) yield break; _backgroundSpriteRenderer.gameObject.SetActive(true); if (duration <= 0f) _backgroundSpriteRenderer.SetAlpha(1f); else yield return _backgroundSpriteRenderer.DOFade(1f, duration).WaitForCompletion(); } public IEnumerator FadeOutAsync(float duration = 1f) { if (_backgroundSpriteRenderer == null) yield break; _backgroundSpriteRenderer.gameObject.SetActive(true); if (duration > 0f) yield return _backgroundSpriteRenderer.DOFade(0f, duration).WaitForCompletion(); SetBackgroundImmediate(false); } public void FadeInSync(float duration = 1f) { StartCoroutine(FadeInAsync(duration)); } public void FadeOutSync(float duration = 1f) { StartCoroutine(FadeOutAsync(duration)); } public void ClearPresentationEffects() { NotifyPresentationChanging(); ClearSmallImmediate(); ClearLargeImmediate(); SetBackgroundImmediate(false); } public ShowcaseSnapshotDto CaptureSnapshot() { var mode = ShowcaseDisplayMode.None; var picName = string.Empty; if (IsSmallShowing && !string.IsNullOrEmpty(_currentSmallPicName)) { mode = ShowcaseDisplayMode.Small; picName = _currentSmallPicName; } else if (IsLargeShowing && !string.IsNullOrEmpty(_currentLargePicName)) { mode = ShowcaseDisplayMode.Large; picName = _currentLargePicName; } return new ShowcaseSnapshotDto { displayMode = mode.ToString(), picName = picName, isBackgroundVisible = _backgroundSpriteRenderer != null && _backgroundSpriteRenderer.gameObject.activeSelf && _backgroundSpriteRenderer.color.a > 0.001f }; } public IEnumerator RestoreSnapshotAsync(ShowcaseSnapshotDto snapshot, Action warning = null) { ClearPresentationEffects(); if (snapshot == null) yield break; if (!Enum.TryParse(snapshot.displayMode, true, out ShowcaseDisplayMode mode)) { warning?.Invoke($"[SpriteShowcase] Unknown display mode: {snapshot.displayMode}"); mode = ShowcaseDisplayMode.None; } switch (mode) { case ShowcaseDisplayMode.Small when !string.IsNullOrWhiteSpace(snapshot.picName): yield return ShowObj(snapshot.picName, 0f); break; case ShowcaseDisplayMode.Large when !string.IsNullOrWhiteSpace(snapshot.picName): yield return ShowLargeObj(snapshot.picName, 0f); break; } SetBackgroundImmediate(snapshot.isBackgroundVisible); } private void NotifyPresentationChanging() { PresentationChanging?.Invoke(); } private void ClearSmallImmediate() { if (_spriteRenderer != null) { _spriteRenderer.DOKill(); _spriteRenderer.SetAlpha(0f); _spriteRenderer.gameObject.SetActive(false); } _currentSmallPicName = null; } private void ClearLargeImmediate() { if (_largeSpriteRenderer != null) { _largeSpriteRenderer.DOKill(); _largeSpriteRenderer.SetAlpha(0f); _largeSpriteRenderer.gameObject.SetActive(false); } _currentLargePicName = null; } private void SetBackgroundImmediate(bool visible) { if (_backgroundSpriteRenderer == null) return; _backgroundSpriteRenderer.DOKill(); _backgroundSpriteRenderer.SetAlpha(visible ? 1f : 0f); _backgroundSpriteRenderer.gameObject.SetActive(visible); } } }