132 lines
5.2 KiB
C#
132 lines
5.2 KiB
C#
using System.Collections;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace BaseGames.UI
|
||
{
|
||
/// <summary>
|
||
/// UI 协程补间静态库。
|
||
///
|
||
/// 设计动机:消除 <see cref="BossHPBar"/>、<see cref="ToastNotification"/>、
|
||
/// <see cref="FloatingDamageText"/> 等组件中重复出现的 Lerp + WaitForEndOfFrame 样板,
|
||
/// 集中维护时间步与回调约定。所有协程默认使用 <see cref="Time.unscaledDeltaTime"/>,
|
||
/// 以便 UI 动画在游戏暂停(<see cref="Time.timeScale"/> = 0)时仍能播放。
|
||
///
|
||
/// 性能特征:
|
||
/// · 无堆分配(除协程对象本身);
|
||
/// · 提前返回保护无效目标;
|
||
/// · <paramref name="duration"/> <= 0 时立即吸附到终态并退出(一帧 yield 用于保持
|
||
/// 与正常协程一致的栈语义)。
|
||
/// </summary>
|
||
public static class UITween
|
||
{
|
||
// ── 位置 ─────────────────────────────────────────────────────────────
|
||
|
||
/// <summary>将 RectTransform 的 anchoredPosition 平滑过渡到目标值。</summary>
|
||
public static IEnumerator MoveAnchored(RectTransform rect,
|
||
Vector2 target,
|
||
float duration,
|
||
bool unscaled = true)
|
||
{
|
||
if (rect == null) yield break;
|
||
if (duration <= 0f)
|
||
{
|
||
rect.anchoredPosition = target;
|
||
yield break;
|
||
}
|
||
|
||
Vector2 start = rect.anchoredPosition;
|
||
float t = 0f;
|
||
while (t < duration)
|
||
{
|
||
rect.anchoredPosition = Vector2.Lerp(start, target, t / duration);
|
||
t += unscaled ? Time.unscaledDeltaTime : Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
rect.anchoredPosition = target;
|
||
}
|
||
|
||
// ── 透明度 ───────────────────────────────────────────────────────────
|
||
|
||
/// <summary>将 CanvasGroup.alpha 平滑过渡到目标值。</summary>
|
||
public static IEnumerator FadeCanvasGroup(CanvasGroup cg,
|
||
float target,
|
||
float duration,
|
||
bool unscaled = true)
|
||
{
|
||
if (cg == null) yield break;
|
||
if (duration <= 0f)
|
||
{
|
||
cg.alpha = target;
|
||
yield break;
|
||
}
|
||
|
||
float start = cg.alpha;
|
||
float t = 0f;
|
||
while (t < duration)
|
||
{
|
||
cg.alpha = Mathf.Lerp(start, target, t / duration);
|
||
t += unscaled ? Time.unscaledDeltaTime : Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
cg.alpha = target;
|
||
}
|
||
|
||
/// <summary>将 Graphic(Image / TMP_Text 等)的颜色 Alpha 通道平滑过渡到目标值。</summary>
|
||
public static IEnumerator FadeGraphic(Graphic graphic,
|
||
float targetAlpha,
|
||
float duration,
|
||
bool unscaled = true)
|
||
{
|
||
if (graphic == null) yield break;
|
||
if (duration <= 0f)
|
||
{
|
||
var c = graphic.color;
|
||
c.a = targetAlpha;
|
||
graphic.color = c;
|
||
yield break;
|
||
}
|
||
|
||
float startAlpha = graphic.color.a;
|
||
float t = 0f;
|
||
while (t < duration)
|
||
{
|
||
var c = graphic.color;
|
||
c.a = Mathf.Lerp(startAlpha, targetAlpha, t / duration);
|
||
graphic.color = c;
|
||
t += unscaled ? Time.unscaledDeltaTime : Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
var fc = graphic.color;
|
||
fc.a = targetAlpha;
|
||
graphic.color = fc;
|
||
}
|
||
|
||
// ── 缩放 ─────────────────────────────────────────────────────────────
|
||
|
||
/// <summary>将 Transform 的 localScale 等比平滑过渡到目标值。</summary>
|
||
public static IEnumerator Scale(Transform tr,
|
||
Vector3 target,
|
||
float duration,
|
||
bool unscaled = true)
|
||
{
|
||
if (tr == null) yield break;
|
||
if (duration <= 0f)
|
||
{
|
||
tr.localScale = target;
|
||
yield break;
|
||
}
|
||
|
||
Vector3 start = tr.localScale;
|
||
float t = 0f;
|
||
while (t < duration)
|
||
{
|
||
tr.localScale = Vector3.Lerp(start, target, t / duration);
|
||
t += unscaled ? Time.unscaledDeltaTime : Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
tr.localScale = target;
|
||
}
|
||
}
|
||
}
|