103 lines
3.4 KiB
C#
103 lines
3.4 KiB
C#
using System;
|
||
using DG.Tweening; // 引入 DOTween
|
||
using UnityEngine;
|
||
using SLSUtilities.UI;
|
||
|
||
namespace Cielonos.Core.UI
|
||
{
|
||
// 继承 UIElementBase,同时实现简单的单例逻辑
|
||
public class ScreenFader : UIElementBase
|
||
{
|
||
public static ScreenFader Instance { get; private set; }
|
||
|
||
[Header("Settings")]
|
||
[SerializeField] private float defaultDuration = 0.5f;
|
||
[SerializeField] private bool startBlack = true;
|
||
[SerializeField] private Ease fadeEase = Ease.InOutQuad; // 暴露曲线设置,比 SmoothStep 更灵活
|
||
|
||
private Tween currentTween; // 记录当前动画,防止冲突
|
||
|
||
private void Awake()
|
||
{
|
||
// --- 单例逻辑 ---
|
||
if (Instance != null && Instance != this)
|
||
{
|
||
Destroy(gameObject);
|
||
return;
|
||
}
|
||
Instance = this;
|
||
// ----------------
|
||
|
||
// 初始化状态
|
||
if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>();
|
||
|
||
if (startBlack)
|
||
{
|
||
canvasGroup.alpha = 1f;
|
||
canvasGroup.blocksRaycasts = true;
|
||
}
|
||
else
|
||
{
|
||
canvasGroup.alpha = 0f;
|
||
canvasGroup.blocksRaycasts = false;
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 这是一个好习惯:销毁时杀掉所有未完成的动画,防止报错
|
||
currentTween?.Kill();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 变黑 (Fade Out / 遮挡屏幕)
|
||
/// </summary>
|
||
public Tween FadeToBlack(float duration = -1, Action onComplete = null)
|
||
{
|
||
return FadeTo(1f, duration, onComplete);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 变亮 (Fade In / 显示屏幕)
|
||
/// </summary>
|
||
public Tween FadeToClear(float duration = -1, float delay = 1, Action onComplete = null)
|
||
{
|
||
return FadeTo(0f, duration, onComplete).SetDelay(delay);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通用淡入淡出逻辑
|
||
/// 返回 Tween 对象,允许外部使用 yield return tween.WaitForCompletion();
|
||
/// </summary>
|
||
private Tween FadeTo(float targetAlpha, float duration, Action onComplete)
|
||
{
|
||
// 1. 如果有正在运行的动画,立刻杀掉,确保从当前 alpha 开始新的变化
|
||
currentTween?.Kill();
|
||
|
||
float d = duration < 0 ? defaultDuration : duration;
|
||
|
||
// 2. 只有在变黑(alpha -> 1)开始时,才阻挡射线
|
||
// 这样防止玩家在变黑过程中还能点击后面的按钮
|
||
if (targetAlpha > 0.5f)
|
||
{
|
||
canvasGroup.blocksRaycasts = true;
|
||
}
|
||
|
||
// 3. 使用 DOTween
|
||
currentTween = canvasGroup.DOFade(targetAlpha, d)
|
||
.SetEase(fadeEase)
|
||
.SetUpdate(true) // 【关键】忽略 TimeScale,游戏暂停时依然可以淡入淡出
|
||
.OnComplete(() =>
|
||
{
|
||
// 只有在完全变亮(alpha -> 0)结束后,才取消阻挡
|
||
if (targetAlpha < 0.01f)
|
||
{
|
||
canvasGroup.blocksRaycasts = false;
|
||
}
|
||
onComplete?.Invoke();
|
||
});
|
||
|
||
return currentTween;
|
||
}
|
||
}
|
||
} |