UI相关优化补充

This commit is contained in:
2026-05-25 13:21:41 +08:00
parent 3c812cfb41
commit a1f9122153
54 changed files with 2008 additions and 112 deletions

View File

@@ -9,8 +9,8 @@ namespace BaseGames.UI
{
/// <summary>
/// 伤害飘字(架构 10_UIModule §10
/// 从对象池取出后由 FloatingDamageSpawner 调用 Show()协程完成后归还。
/// 挂在预制体根 GameObject 上Canvas_HUD 子节点World Space Canvas 或 Screen Space
/// 从对象池取出后由 FloatingDamageSpawner 调用 Show()
/// 动画推进由 <see cref="FloatingDamageTickSystem"/> 统一调度,避免大量独立协程
/// </summary>
public class FloatingDamageText : MonoBehaviour
{
@@ -26,8 +26,7 @@ namespace BaseGames.UI
[SerializeField] private Canvas _parentCanvas;
private RectTransform _rectTransform;
private Coroutine _animCoroutine;
// 每次 Show() 解析一次,协程期间(< 1s复用避免每帧走 FindObjectByTag
// 每次 Show() 解析一次,动画期间(< 1s复用避免每帧走 FindObjectByTag
private Camera _cachedCamera;
private void Awake()
@@ -36,15 +35,15 @@ namespace BaseGames.UI
}
/// <summary>
/// 在世界坐标位置显示伤害数字并开始飘动动画。
/// 动画结束后由对象池回收Deactivate
/// 在世界坐标位置显示伤害数字并启动飘动动画。
/// 动画结束后由 OnTickComplete 回调列表 SetActive(false)
/// </summary>
public void Show(Vector2 worldPosition, int damage, DamageType type)
{
if (_animCoroutine != null) StopCoroutine(_animCoroutine);
// 取消上一条动画(如果被预期复用)
FloatingDamageTickSystem.Instance.Unregister(this);
// 每次 Show 解析一次摄像机:动画时长 < 1s期间不会切换主摄像机
// 若 Boss 过场后再次 Show会自动获取新的主摄像机。
// 每次 Show 解析一次摄像机
_cachedCamera = (_parentCanvas != null && _parentCanvas.renderMode == RenderMode.ScreenSpaceCamera)
? _parentCanvas.worldCamera
: UnityEngine.Camera.main;
@@ -53,9 +52,22 @@ namespace BaseGames.UI
_text.color = GetColorForType(type);
SetAnchoredPosition(worldPosition);
_animCoroutine = StartCoroutine(FloatAndFade(worldPosition));
FloatingDamageTickSystem.Instance.Register(this, worldPosition,
_duration, _floatDistance, _text.color.a);
}
/// <summary>由 <see cref="FloatingDamageTickSystem"/> 每帧调用t 为归一化进度 [0,1]。</summary>
internal void TickAnimation(Vector2 startWorld, float t, float startAlpha, float floatDistance)
{
SetAnchoredPosition(startWorld + new Vector2(0, floatDistance * t));
var color = _text.color;
color.a = Mathf.Lerp(startAlpha, 0f, Mathf.Clamp01((t - 0.5f) / 0.5f));
_text.color = color;
}
/// <summary>动画结束回调:反激活 GameObject 归还池。</summary>
internal void OnTickComplete() => gameObject.SetActive(false);
private void SetAnchoredPosition(Vector2 worldPosition)
{
var cam = _cachedCamera;
@@ -82,6 +94,7 @@ namespace BaseGames.UI
private IEnumerator FloatAndFade(Vector2 startWorld)
{
// 保留作为 fallback若业务方选择继续使用独立协程可直接调用本方法。
float elapsed = 0f;
var color = _text.color;
var startAlpha = color.a;
@@ -89,18 +102,11 @@ namespace BaseGames.UI
while (elapsed < _duration)
{
float t = elapsed / _duration;
SetAnchoredPosition(startWorld + new Vector2(0, _floatDistance * t));
// alpha 淡出(后半段开始)—— 修改 struct 的 a 分量并回写,避免每帧 new Color 堆分配
color.a = Mathf.Lerp(startAlpha, 0f, Mathf.Clamp01((t - 0.5f) / 0.5f));
_text.color = color;
TickAnimation(startWorld, t, startAlpha, _floatDistance);
elapsed += Time.deltaTime;
yield return null;
}
gameObject.SetActive(false); // 归还对象池
OnTickComplete();
}
private static Color GetColorForType(DamageType type) => type switch