好多新内容

This commit is contained in:
2026-07-22 05:35:53 +08:00
parent b5d1cdcbc5
commit 15649d02f8
128 changed files with 5956 additions and 673 deletions
+118 -26
View File
@@ -216,6 +216,9 @@ public class HoldNote : BaseNote
if (controller != null)
{
controller.OnJudgeZoneChanged += OnJudgeZoneChanged;
// 去物理判定:进入/离开判定区的分段逻辑由 controller 几何驱动回调触发(替代自身 OnTrigger)。
controller.OnZoneEnterGeometry += HandleZoneEnter;
controller.OnZoneExitGeometry += HandleZoneExit;
}
cachedJudgeManager = JudgeManager.Instance;
@@ -322,6 +325,8 @@ public class HoldNote : BaseNote
if (controller != null)
{
controller.OnJudgeZoneChanged -= OnJudgeZoneChanged;
controller.OnZoneEnterGeometry -= HandleZoneEnter;
controller.OnZoneExitGeometry -= HandleZoneExit;
}
if (JudgeManager.Instance != null)
@@ -342,13 +347,53 @@ public class HoldNote : BaseNote
private void PlayHitAnimation()
{
var controller = AnimationController.Global ?? anim;
var controller = GetAnimationController();
if (controller != null)
{
controller.PlayDestroyAnimation(noteColor);
}
}
private void PlayMiddleSegmentHitFx()
{
PlayHitAnimation();
TrackJudgeHitEffectController.PlayTrackHitFx(trackIndex);
}
private void EnsureHoldParticleLoop()
{
if (!isHoldActive || string.IsNullOrEmpty(noteColor))
{
return;
}
// 按长音符 id 记账,避免同轨道旧段回收误停当前长按特效。
GetAnimationController()?.StartHoldParticles(noteColor, id);
}
private AnimationController GetAnimationController()
{
if (AnimationController.Global != null)
return AnimationController.Global;
if (anim == null)
{
anim = SceneObjectLookupCache.FindAny<AnimationController>();
}
return anim;
}
private void StartHoldFxLoop()
{
GetAnimationController()?.StartHoldParticles(noteColor, id);
}
private void StopHoldFxLoop()
{
GetAnimationController()?.StopHoldParticles(id);
}
private IEnumerator DelayedDisableAnimation(GameObject animationObject, float delay)
{
// No-op: we used to disable the shared AnimationController here which stopped coroutines.
@@ -481,24 +526,43 @@ public class HoldNote : BaseNote
if (!isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID) && keyHeld)
{
isHoldActive = true;
AnimationController.Global?.StartHoldParticles(noteColor);
StartHoldFxLoop();
if (debugEnabled) Debug.Log($"[HoldNote] Start particles started for {noteID} color={noteColor} at time={now:F3}");
}
if (isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID) && keyHeld)
{
EnsureHoldParticleLoop();
}
// Auto-miss checks when inside judge line
if (hasEnteredLine)
{
float missRangeScaled = (judgeConfig?.missRange ?? 0.5f) * holdWindowMultiplier;
// 只对"尚未判定"的 start 段做超时 auto-Miss。已成功判定的 start 段(玩家已按下、
// 正持续按住)绝不能在此被误判 Miss——否则 EvaluateHoldEnd(forceMiss) 会调 StopHoldParticles
// 把长按持续特效杀掉。物理版时 collider 早已离开判定区不会走到这里;几何版 exit 更晚才暴露此隐患。
bool startAlreadyJudged = jm != null && jm.IsStartJudged(noteID);
if (segment == NoteSegment.Start && now > hitTime + missRangeScaled)
{
if (debugEnabled) Debug.Log($"[HoldNote] START auto-Miss: {noteColor}");
// Register miss properly via EvaluateHoldEnd
EvaluateHoldEnd(now, true);
isJudged = true;
ScheduleReturnToPool(0.2f);
return;
if (!startAlreadyJudged)
{
if (debugEnabled) Debug.Log($"[HoldNote] START auto-Miss: {noteColor}");
// 未判定的 start 超时 → 正常 Miss。
EvaluateHoldEnd(now, true);
isJudged = true;
ScheduleReturnToPool(0.2f);
return;
}
else
{
// 已成功判定的 start 段:其视觉/判定使命已完成(end 段负责收尾),
// 静默回收即可,绝不能走 EvaluateHoldEnd(会 StopHoldParticles 杀掉长按持续特效)。
// isHoldActive 由 middle/end 段各自维持,不受本段回收影响。
isJudged = true;
ScheduleReturnToPool(0.2f);
return;
}
}
else if (segment == NoteSegment.End && now > scheduledEndTime + missRangeScaled)
@@ -515,7 +579,7 @@ public class HoldNote : BaseNote
if (isHoldActive && keyUp)
{
isHoldActive = false;
AnimationController.Global?.StopHoldParticles();
StopHoldFxLoop();
if (debugEnabled) Debug.Log($"[HoldNote] KeyUp {keyToPress} detected. NoteID: {noteID}, Segment: {segment}, Type: {type}");
if (!hasReleased)
@@ -571,15 +635,18 @@ public class HoldNote : BaseNote
}
else if (segment == NoteSegment.Middle
&& jm != null && jm.IsStartJudged(noteID)
&& isHoldActive
&& keyHeld
&& !jm.HasNoteReleased(noteID))
{
isHoldActive = true;
EnsureHoldParticleLoop();
if (now >= hitTime)
{
if (hasEnteredLine)
{
if (JudgeManager.IsDebugEnabled) Debug.Log($"[HoldNote] Middle passed: {noteColor}");
PlayHitAnimation();
// 按住阶段粒子由 AnimationController 的固定 tick 统一生成。
// 中段经过只负责保持循环,不额外加打一组,避免长音符前半段因中段密集而粒子频率过高。
jm?.RegisterMiddlePassed(noteID);
ScheduleReturnToPool(0.2f);
isJudged = true;
@@ -610,6 +677,11 @@ public class HoldNote : BaseNote
isHoldActive = true;
}
if (isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID))
{
EnsureHoldParticleLoop();
}
if (segment == NoteSegment.Start)
{
bool startResolved = jm != null && jm.IsStartJudged(noteID);
@@ -642,7 +714,7 @@ public class HoldNote : BaseNote
if (now >= hitTime && hasEnteredLine)
{
if (debugEnabled) Debug.Log($"[HoldNote.AutoPlay] Middle passed: {noteColor}");
PlayHitAnimation();
// 按住阶段粒子由 AnimationController 的固定 tick 统一生成。
jm?.RegisterMiddlePassed(noteID);
ScheduleReturnToPool(0.2f);
isJudged = true;
@@ -690,7 +762,7 @@ public class HoldNote : BaseNote
JudgeManager.Instance.RegisterStartJudged(noteID, true);
isHoldActive = true;
PlayHitAnimation();
AnimationController.Global?.StartHoldParticles(noteColor);
StartHoldFxLoop();
holdStartTime = pressTime;
HoldNoteJudgePool.RegisterStart(noteID, pressTime, hitTime, scheduledEndTime, noteColor, trackIndex, (object)noteData);
@@ -707,10 +779,9 @@ public class HoldNote : BaseNote
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
}
private void OnTriggerEnter2D(Collider2D collision)
// 去物理判定:原 OnTriggerEnter2D 的分段逻辑,改由 controller 几何驱动调用,逻辑完全一致。
private void HandleZoneEnter()
{
if (!collision.CompareTag("JudgmentLine")) return;
hasEnteredLine = true;
if (segment == NoteSegment.Start)
@@ -753,7 +824,7 @@ public class HoldNote : BaseNote
isJudged = true;
// Terminate input - mark key as released
isHoldActive = false;
AnimationController.Global?.StopHoldParticles();
StopHoldFxLoop();
return;
}
@@ -761,10 +832,9 @@ public class HoldNote : BaseNote
}
}
private void OnTriggerExit2D(Collider2D collision)
// 去物理判定:原 OnTriggerExit2D 的分段逻辑,改由 controller 几何驱动调用,逻辑完全一致。
private void HandleZoneExit()
{
if (!collision.CompareTag("JudgmentLine")) return;
if (segment == NoteSegment.Start)
{
UnregisterQueueIfNeeded();
@@ -922,7 +992,7 @@ public class HoldNote : BaseNote
JudgeManager.Instance.RegisterStartJudged(noteID, true);
isHoldActive = true;
PlayHitAnimation();
AnimationController.Global?.StartHoldParticles(noteColor);
StartHoldFxLoop();
// record when the hold started so we can compute held fraction later
holdStartTime = pressTime;
@@ -938,7 +1008,7 @@ public class HoldNote : BaseNote
JudgeManager.Instance.RegisterStartJudged(noteID, true);
isHoldActive = true;
PlayHitAnimation();
AnimationController.Global?.StartHoldParticles(noteColor);
StartHoldFxLoop();
holdStartTime = pressTime;
@@ -952,7 +1022,7 @@ public class HoldNote : BaseNote
JudgeManager.Instance.RegisterStartJudged(noteID, true);
isHoldActive = true;
PlayHitAnimation();
AnimationController.Global?.StartHoldParticles(noteColor);
StartHoldFxLoop();
holdStartTime = pressTime;
@@ -1260,7 +1330,21 @@ public class HoldNote : BaseNote
if (JudgeManager.IsDebugEnabled) Debug.Log($"[HoldNote] Hold end NotifyNoteHit called: TrackIndex={TrackIndex} trackIndexField={trackIndex} result={result} triggeredHold={triggeredHold} triggeredTap={triggeredTap}");
}
AnimationController.Global?.StopHoldParticles();
// 只有命中(非 Miss)才播放打击特效;Miss 不该触发击打效果。
// 与上面 1253-1256 的 TrackJudgeHitEffectController 守卫保持一致。
if (result != "Miss")
{
PlayHitAnimation();
}
// 关键修复(长条结束仍按住→持续特效不停):hold 已完整结算,标记该 note 为"已释放/已完结"。
// 否则玩家继续按住时,其它仍存活的段 Update 满足 (isHoldActive && IsStartJudged && !HasNoteReleased
// && keyHeld) 会再次 EnsureHoldParticleLoop 重启持续 tick——即使 hold 逻辑上已经结束。
// 置 released 后,所有段的 Update 门槛 !HasNoteReleased 不再成立,持续循环不会被重启。
hasReleased = true;
JudgeManager.Instance?.RegisterNoteReleased(noteID, true);
StopHoldFxLoop();
// Release the track lock immediately after end evaluation so the next hold can start on time
ReleaseTrackJudgeLockSafe();
@@ -1390,10 +1474,18 @@ public class HoldNote : BaseNote
hitTime = 0f;
scheduledEndTime = 0f;
hasEnteredLine = false;
// 普通 start/middle 段回收时,同一条长音符可能仍在持续按住,不能在这里停掉持续特效。
// 真正停止由 keyUp / end 判定路径负责;这里只兜底处理 end 段池化泄漏。
if (isHoldActive && segment == NoteSegment.End)
{
StopHoldFxLoop();
}
isJudged = false;
isHoldActive = false;
hasBeenHeldFromStart = false;
prevTrackHeld = false;
// 去物理判定:池化复用时重置 controller 的几何判定状态(重新算阈值、清进入标志)。
if (controller != null) controller.ResetJudgeZoneGeometry();
holdStartTime = -1f;