超大量的更新 修复很多问题,gameplay特效初步
This commit is contained in:
@@ -12,7 +12,6 @@ public class HoldNote : BaseNote
|
||||
private string noteID = string.Empty;
|
||||
private NoteSegment segment = NoteSegment.None;
|
||||
|
||||
private new float hitTime = 0f;
|
||||
private float releaseTime = 0f;
|
||||
private bool hasReleased = true;
|
||||
private bool hasEnteredLine = false;
|
||||
@@ -68,6 +67,7 @@ public class HoldNote : BaseNote
|
||||
|
||||
// Cache allies per track to avoid GameObject.Find on first judgement.
|
||||
private static AllyCombatant[] allyCache;
|
||||
private static BeatmapManager beatmapManagerCache;
|
||||
|
||||
private struct RendererMaterialCache
|
||||
{
|
||||
@@ -92,6 +92,40 @@ public class HoldNote : BaseNote
|
||||
return allyCache[trackIndex];
|
||||
}
|
||||
|
||||
private static BeatmapManager GetBeatmapManagerCached()
|
||||
{
|
||||
if (beatmapManagerCache != null) return beatmapManagerCache;
|
||||
beatmapManagerCache = Object.FindAnyObjectByType<BeatmapManager>();
|
||||
return beatmapManagerCache;
|
||||
}
|
||||
|
||||
private static float JudgeToPmMultiplier(string judgeResult)
|
||||
{
|
||||
switch (judgeResult)
|
||||
{
|
||||
case "Perfect": return 1f;
|
||||
case "Great": return 0.75f;
|
||||
case "Good": return 0.5f;
|
||||
case "Miss": return 0f;
|
||||
default: return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private static int ComputePmDeltaFromJudge(string judgeResult, AllyCombatant ally)
|
||||
{
|
||||
int baseScore = 0;
|
||||
|
||||
var bmm = ally != null ? ally.bmm : null;
|
||||
if (bmm == null) bmm = GetBeatmapManagerCached();
|
||||
if (bmm != null) baseScore = Mathf.Max(0, bmm.perNoteScore);
|
||||
|
||||
if (baseScore <= 0 && ally != null) baseScore = Mathf.Max(0, ally.baseTrackScore);
|
||||
if (baseScore <= 0) return 0;
|
||||
|
||||
float mult = JudgeToPmMultiplier(judgeResult);
|
||||
return Mathf.FloorToInt(baseScore * mult);
|
||||
}
|
||||
|
||||
private JudgeManager cachedJudgeManager;
|
||||
private TrackKeyManager cachedTrackKeyManager;
|
||||
|
||||
@@ -362,6 +396,12 @@ public class HoldNote : BaseNote
|
||||
if (now < hitTime - 0.5f) return;
|
||||
}
|
||||
|
||||
if (GameConfig.autoPlayEnabled)
|
||||
{
|
||||
UpdateAutoplay(now, jm, tkm, debugEnabled);
|
||||
return;
|
||||
}
|
||||
|
||||
bool keyHeld = Input.GetKey(keyToPress);
|
||||
bool keyDown = Input.GetKeyDown(keyToPress);
|
||||
bool keyUp = Input.GetKeyUp(keyToPress);
|
||||
@@ -491,6 +531,104 @@ public class HoldNote : BaseNote
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAutoplay(float now, JudgeManager jm, TrackKeyManager tkm, bool debugEnabled)
|
||||
{
|
||||
// Keep the "hold active" state alive for middle/end segments once the start has been judged.
|
||||
if (!isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID))
|
||||
{
|
||||
isHoldActive = true;
|
||||
}
|
||||
|
||||
if (segment == NoteSegment.Start)
|
||||
{
|
||||
bool startResolved = jm != null && jm.IsStartJudged(noteID);
|
||||
if (!startResolved && now >= hitTime)
|
||||
{
|
||||
// Ensure we are the front-most note in the judge queue (if any)
|
||||
var headId = tkm?.GetCurrentNoteId(trackIndex);
|
||||
if (headId != null && headId != queueNoteId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float pressTimeLocal = hitTime; // force Perfect regardless of frame timing
|
||||
float maxWindow = (judgeConfig?.missRange ?? 0.5f) * holdWindowMultiplier;
|
||||
|
||||
if (tkm != null && !tkm.IsBestCandidate(trackIndex, queueNoteId, pressTimeLocal, maxWindow))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandleStartAutoplayPerfect(pressTimeLocal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (segment == NoteSegment.Middle)
|
||||
{
|
||||
if (jm != null && jm.IsStartJudged(noteID) && isHoldActive && !jm.HasNoteReleased(noteID))
|
||||
{
|
||||
if (now >= hitTime && hasEnteredLine)
|
||||
{
|
||||
if (debugEnabled) Debug.Log($"[HoldNote.AutoPlay] Middle passed: {noteColor}");
|
||||
PlayHitAnimation();
|
||||
jm?.RegisterMiddlePassed(noteID);
|
||||
ScheduleReturnToPool(0.2f);
|
||||
isJudged = true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (segment == NoteSegment.End)
|
||||
{
|
||||
if (jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID))
|
||||
{
|
||||
if (now >= scheduledEndTime)
|
||||
{
|
||||
// Defensive: ensure pool info exists so EvaluateHoldEnd resolves to Perfect deterministically.
|
||||
if (!HoldNoteJudgePool.TryGet(noteID, out _))
|
||||
{
|
||||
if (noteData != null) noteData.judgeOffsetMs = 0f;
|
||||
HoldNoteJudgePool.RegisterStart(noteID, hitTime, hitTime, scheduledEndTime, noteColor, trackIndex, (object)noteData);
|
||||
}
|
||||
|
||||
EvaluateHoldEnd(scheduledEndTime, false);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStartAutoplayPerfect(float pressTime)
|
||||
{
|
||||
// release from queue so following notes can become head
|
||||
UnregisterQueueIfNeeded();
|
||||
|
||||
if (!JudgeManager.Instance.TryResolveStart(noteID))
|
||||
{
|
||||
if (JudgeManager.IsDebugEnabled) Debug.Log($"[HoldNote.AutoPlay] START try-resolve failed: {noteColor}");
|
||||
return;
|
||||
}
|
||||
|
||||
const string result = "Perfect";
|
||||
|
||||
float rawOffsetMs = (hitTime - pressTime) * 1000f;
|
||||
if (noteData != null) noteData.judgeOffsetMs = rawOffsetMs;
|
||||
|
||||
JudgeManager.Instance.RegisterStartJudged(noteID, true);
|
||||
isHoldActive = true;
|
||||
PlayHitAnimation();
|
||||
AnimationController.Global?.StartHoldParticles(noteColor);
|
||||
|
||||
holdStartTime = pressTime;
|
||||
HoldNoteJudgePool.RegisterStart(noteID, pressTime, hitTime, scheduledEndTime, noteColor, trackIndex, (object)noteData);
|
||||
|
||||
InputManager.Instance?.ShowJudgeResult(trackIndex, result);
|
||||
teamUIController.Instance?.OnJudgeResult(result);
|
||||
JudgeSoundManager.Instance?.PlayJudgeSound(result);
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (!collision.CompareTag("JudgmentLine")) return;
|
||||
@@ -523,8 +661,9 @@ public class HoldNote : BaseNote
|
||||
return;
|
||||
}
|
||||
|
||||
// NEW: If the key is still being held down when end segment enters judge zone, immediately judge
|
||||
if (Input.GetKey(keyToPress) && JudgeManager.Instance.IsStartJudged(noteID) && !isJudged)
|
||||
// If the key is still being held down when end segment enters judge zone, immediately judge.
|
||||
// Autoplay must ignore physical input to guarantee Perfect at scheduledEndTime.
|
||||
if (!GameConfig.autoPlayEnabled && Input.GetKey(keyToPress) && JudgeManager.Instance.IsStartJudged(noteID) && !isJudged)
|
||||
{
|
||||
if (JudgeManager.IsDebugEnabled) Debug.Log($"[HoldNote] End entered while key still held: {noteColor}, calculating result immediately");
|
||||
// Record release time as current time (player is still holding)
|
||||
@@ -945,12 +1084,11 @@ public class HoldNote : BaseNote
|
||||
try
|
||||
{
|
||||
var ally = GetAllyForTrackCached(TrackIndex);
|
||||
if (ally != null)
|
||||
{
|
||||
int added = ally.AddScoreForJudge(result);
|
||||
float efficiency = ally.scoreEfficiency;
|
||||
ScoreManager.Instance?.AddPmScoreForTrack(TrackIndex, added, efficiency);
|
||||
}
|
||||
if (ally != null) ally.AddScoreForJudge(result);
|
||||
|
||||
int pmDelta = ComputePmDeltaFromJudge(result, ally);
|
||||
float efficiency = (ally != null && !ally.IsDead) ? ally.scoreEfficiency : 0f;
|
||||
ScoreManager.Instance?.AddPmScoreForTrack(TrackIndex, pmDelta, efficiency);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user