备份,准备做双端
This commit is contained in:
@@ -60,6 +60,18 @@ public class TrackJudgeHitEffectController : MonoBehaviour
|
||||
private readonly Dictionary<GameObject, ParticleCacheEntry> particleCache =
|
||||
new Dictionary<GameObject, ParticleCacheEntry>();
|
||||
|
||||
// 【性能】延迟回收改用 Update 轮询,替代每命中 StartCoroutine + new WaitForSecondsRealtime 的分配。
|
||||
// dueUnscaledTime 用 Time.unscaledTime 记录到期时刻,与原 WaitForSecondsRealtime(realtime)语义一致;
|
||||
// token 校验也原样保留,故回收时机与行为完全等效,仅消除每命中的协程/等待对象 GC。
|
||||
private struct PendingParticleReturn
|
||||
{
|
||||
public GameObject Instance;
|
||||
public ParticleCacheEntry Entry;
|
||||
public int RentToken;
|
||||
public float DueUnscaledTime;
|
||||
}
|
||||
private readonly List<PendingParticleReturn> pendingParticleReturns = new List<PendingParticleReturn>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
@@ -299,7 +311,39 @@ public class TrackJudgeHitEffectController : MonoBehaviour
|
||||
Color tint = GetTrackColor(trackIndex);
|
||||
ApplyParticleColor(entry, tint);
|
||||
|
||||
StartCoroutine(RecycleParticleRoutine(instance, entry, CurrentParticleRentToken(instance), Mathf.Max(0.05f, entry.Lifetime)));
|
||||
// 入队延迟回收(Update 轮询),替代每命中 StartCoroutine + WaitForSecondsRealtime 分配。等效。
|
||||
float delay = Mathf.Max(0.05f, entry.Lifetime);
|
||||
pendingParticleReturns.Add(new PendingParticleReturn
|
||||
{
|
||||
Instance = instance,
|
||||
Entry = entry,
|
||||
RentToken = CurrentParticleRentToken(instance),
|
||||
DueUnscaledTime = Time.unscaledTime + delay
|
||||
});
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (pendingParticleReturns.Count == 0)
|
||||
return;
|
||||
|
||||
float nowUnscaled = Time.unscaledTime;
|
||||
for (int i = pendingParticleReturns.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var pending = pendingParticleReturns[i];
|
||||
if (nowUnscaled < pending.DueUnscaledTime)
|
||||
continue;
|
||||
|
||||
pendingParticleReturns.RemoveAt(i);
|
||||
|
||||
// 与原 RecycleParticleRoutine 等效:实例已毁或已被重新租用(token 变了)则不回收。
|
||||
if (pending.Instance == null)
|
||||
continue;
|
||||
if (CurrentParticleRentToken(pending.Instance) != pending.RentToken)
|
||||
continue;
|
||||
|
||||
ReturnParticleInstance(pending.Instance, pending.Entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Prewarm the track particle pool during load so the first judge does not pay
|
||||
@@ -407,20 +451,8 @@ public class TrackJudgeHitEffectController : MonoBehaviour
|
||||
return instance != null && particleRentIds.TryGetValue(instance, out int token) ? token : -1;
|
||||
}
|
||||
|
||||
private IEnumerator RecycleParticleRoutine(GameObject instance, ParticleCacheEntry entry, int rentToken, float delay)
|
||||
{
|
||||
// Short visual FX should always recycle in real time. Tying them to
|
||||
// GameplayClock can leak rented objects while the song clock is paused.
|
||||
yield return new WaitForSecondsRealtime(Mathf.Max(0f, delay));
|
||||
|
||||
if (instance == null)
|
||||
yield break;
|
||||
|
||||
if (CurrentParticleRentToken(instance) != rentToken)
|
||||
yield break;
|
||||
|
||||
ReturnParticleInstance(instance, entry);
|
||||
}
|
||||
// 说明:原 RecycleParticleRoutine 协程(每命中 StartCoroutine + new WaitForSecondsRealtime)已由
|
||||
// Update 轮询的 pendingParticleReturns 替代,回收时机(unscaled/realtime)与 token 校验语义完全一致。
|
||||
|
||||
private void ReturnParticleInstance(GameObject instance, ParticleCacheEntry entry)
|
||||
{
|
||||
@@ -459,6 +491,9 @@ public class TrackJudgeHitEffectController : MonoBehaviour
|
||||
particleCache.TryGetValue(instance, out var entry);
|
||||
ReturnParticleInstance(instance, entry);
|
||||
}
|
||||
|
||||
// 所有租用粒子已强制回收,清空延迟回收队列避免残留项(与原协程在 OnDisable/OnDestroy 随之停止等效)。
|
||||
pendingParticleReturns.Clear();
|
||||
}
|
||||
|
||||
private Color GetTrackColor(int trackIndex)
|
||||
|
||||
Reference in New Issue
Block a user