Files
aibis-dream/Assets/Scripts/SceneManagement/SpriteShowcase.cs
T

303 lines
10 KiB
C#

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
{
/// <summary>
/// 梦境场景通用图片展示器。只负责普通小图、大图与背景遮罩;
/// 场景专属动态表现通过 <see cref="PresentationChanging"/> 与本组件解耦。
/// </summary>
public class SpriteShowcase : Singleton<SpriteShowcase>
{
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<bool> completed = null,
Action<string> warning = null)
{
if (target == null)
{
completed?.Invoke(false);
yield break;
}
var key = string.Format(DreamSpritePath, NormalizeDreamPicName(picName));
var handle = ResourceSystem.LoadAsync<Sprite>(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<string> 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);
}
}
}