103 lines
3.6 KiB
C#
103 lines
3.6 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.UI
|
||
{
|
||
/// <summary>
|
||
/// 全局伤害飘字 Tick 系统(架构 10_UIModule §10 优化)。
|
||
///
|
||
/// 设计动机:原实现中每条飘字独立 StartCoroutine(FloatAndFade),
|
||
/// Boss 战或大范围 AOE 时同时存在数十条会产生大量协程对象与调度开销。
|
||
/// 本系统用单一 Update + 紧凑 List<Entry> 集中推进,
|
||
/// 所有飘字共享同一份每帧调度(仅一次 Update 调用),并消除协程对象。
|
||
///
|
||
/// 使用:FloatingDamageText.Show 不再 StartCoroutine,而是调用
|
||
/// FloatingDamageTickSystem.Register(this, ...);系统自动在动画结束时
|
||
/// 调用 OnComplete 回调(飘字 SetActive(false) 回池)。
|
||
/// </summary>
|
||
[DefaultExecutionOrder(+100)]
|
||
public class FloatingDamageTickSystem : MonoBehaviour
|
||
{
|
||
private struct Entry
|
||
{
|
||
public FloatingDamageText Target;
|
||
public Vector2 StartWorld;
|
||
public float Elapsed;
|
||
public float Duration;
|
||
public float FloatDistance;
|
||
public float StartAlpha;
|
||
}
|
||
|
||
private static FloatingDamageTickSystem s_instance;
|
||
private readonly List<Entry> _entries = new(64);
|
||
|
||
public static FloatingDamageTickSystem Instance
|
||
{
|
||
get
|
||
{
|
||
if (s_instance != null) return s_instance;
|
||
var go = new GameObject(nameof(FloatingDamageTickSystem));
|
||
DontDestroyOnLoad(go);
|
||
s_instance = go.AddComponent<FloatingDamageTickSystem>();
|
||
return s_instance;
|
||
}
|
||
}
|
||
|
||
private void Awake()
|
||
{
|
||
if (s_instance != null && s_instance != this) { Destroy(this); return; }
|
||
s_instance = this;
|
||
}
|
||
|
||
public void Register(FloatingDamageText target, Vector2 startWorld,
|
||
float duration, float floatDistance, float startAlpha)
|
||
{
|
||
if (target == null || duration <= 0f) return;
|
||
_entries.Add(new Entry
|
||
{
|
||
Target = target,
|
||
StartWorld = startWorld,
|
||
Elapsed = 0f,
|
||
Duration = duration,
|
||
FloatDistance = floatDistance,
|
||
StartAlpha = startAlpha
|
||
});
|
||
}
|
||
|
||
/// <summary>取消指定目标的飘字动画(例如对象池回收)。</summary>
|
||
public void Unregister(FloatingDamageText target)
|
||
{
|
||
for (int i = _entries.Count - 1; i >= 0; i--)
|
||
if (_entries[i].Target == target) _entries.RemoveAt(i);
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
float dt = Time.deltaTime;
|
||
// 倒序遍历,便于安全 RemoveAt
|
||
for (int i = _entries.Count - 1; i >= 0; i--)
|
||
{
|
||
var e = _entries[i];
|
||
if (e.Target == null) { _entries.RemoveAt(i); continue; }
|
||
|
||
e.Elapsed += dt;
|
||
float t = e.Elapsed / e.Duration;
|
||
bool done = t >= 1f;
|
||
if (done) t = 1f;
|
||
|
||
e.Target.TickAnimation(e.StartWorld, t, e.StartAlpha, e.FloatDistance);
|
||
|
||
if (done)
|
||
{
|
||
e.Target.OnTickComplete();
|
||
_entries.RemoveAt(i);
|
||
}
|
||
else
|
||
{
|
||
_entries[i] = e;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|