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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|