成就系统 巨大修改 新的ui 黑白效果 等一堆
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class NoteSpawner : MonoBehaviour
|
||||
{
|
||||
public event Action AllNotesSpawned; // invoked when all notes have been spawned
|
||||
|
||||
public NotePool notePool; // 引用 NotePool
|
||||
public Transform[] spawnPoints; // 对应轨道的生成点
|
||||
public GameObject[] notePrefabs; // 短音符预制体
|
||||
@@ -42,6 +47,19 @@ public class NoteSpawner : MonoBehaviour
|
||||
[Tooltip("When enabled, spawn positioning will compensate each segment's position based on its own activation time so newly spawned segments appear at their expected traveled position. Default: OFF.")]
|
||||
public bool enableYOffsetCompensation = false;
|
||||
|
||||
[Header("Immediate Settlement")]
|
||||
[Tooltip("Optional. If set, this will be used to trigger settlement UI (JudgeManager.TriggerAllNotesJudged). If null, will fall back to JudgeManager.Instance.")]
|
||||
public JudgeManager judgeManager;
|
||||
|
||||
[Tooltip("Optional UI Button. When clicked, will immediately stop spawning and enter settlement.")]
|
||||
public Button immediateSettlementButton;
|
||||
|
||||
[Tooltip("Optional: the pause UI GameObject to disable when immediate settlement is triggered.")]
|
||||
public GameObject pausePanel;
|
||||
|
||||
[Tooltip("Optional: animations GameObject to disable when entering settlement. Will be restored on Start().")]
|
||||
public GameObject animations;
|
||||
|
||||
// optional: constants for runtime clamping (kept for internal use)
|
||||
private const float SpeedMultiplierMin = 0.8f;
|
||||
private const float SpeedMultiplierMax = 1.25f;
|
||||
@@ -54,8 +72,17 @@ public class NoteSpawner : MonoBehaviour
|
||||
|
||||
private static int holdNoteIdCounter = 0; // 全局唯一长音符 ID 计数器
|
||||
|
||||
// map from beatmap note index -> assigned holdNoteId (for hold notes only)
|
||||
private Dictionary<int, int> noteIndexToHoldId = new Dictionary<int, int>();
|
||||
|
||||
private const string NoteSpeedPrefKey = "noteSpeedMultiplier";
|
||||
|
||||
private Coroutine spawnCoroutine;
|
||||
private Coroutine settlementCoroutine;
|
||||
|
||||
// Guard to avoid double-trigger / deadlock
|
||||
private bool immediateSettlementTriggered = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Load saved visual speed multiplier before any spawning logic uses it
|
||||
@@ -65,6 +92,83 @@ public class NoteSpawner : MonoBehaviour
|
||||
if (GameConfig.verboseLogs) Debug.Log($"[NoteSpawner] Loaded speedMultiplier={speedMultiplier} from PlayerPrefs");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// 每次场景启用/加载时:清空立刻结算状态,避免进入场景即锁定
|
||||
ResetImmediateSettlementState();
|
||||
BindImmediateSettlementButton();
|
||||
|
||||
// subscribe to JudgeManager.AllNotesJudged so we disable animations on normal settlement as well
|
||||
TrySubscribeJudgeManager();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// restore animations active state on Start
|
||||
if (animations != null)
|
||||
{
|
||||
try { animations.SetActive(true); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
// ensure subscription if JudgeManager.Instance was not ready during OnEnable
|
||||
TrySubscribeJudgeManager();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnbindImmediateSettlementButton();
|
||||
TryUnsubscribeJudgeManager();
|
||||
}
|
||||
|
||||
private void ResetImmediateSettlementState()
|
||||
{
|
||||
immediateSettlementTriggered = false;
|
||||
// 不强制设置 isSpawning,这个状态由 LoadBeatmap 驱动;这里只清锁
|
||||
}
|
||||
|
||||
private void BindImmediateSettlementButton()
|
||||
{
|
||||
if (immediateSettlementButton == null) return;
|
||||
try { immediateSettlementButton.onClick.RemoveListener(ForceImmediateSettlement); } catch { }
|
||||
immediateSettlementButton.onClick.AddListener(ForceImmediateSettlement);
|
||||
}
|
||||
|
||||
private void UnbindImmediateSettlementButton()
|
||||
{
|
||||
if (immediateSettlementButton == null) return;
|
||||
try { immediateSettlementButton.onClick.RemoveListener(ForceImmediateSettlement); } catch { }
|
||||
}
|
||||
|
||||
private void TrySubscribeJudgeManager()
|
||||
{
|
||||
var jm = judgeManager != null ? judgeManager : JudgeManager.Instance;
|
||||
if (jm != null)
|
||||
{
|
||||
try { jm.AllNotesJudged -= OnSettlementTriggered; } catch { }
|
||||
jm.AllNotesJudged += OnSettlementTriggered;
|
||||
}
|
||||
}
|
||||
|
||||
private void TryUnsubscribeJudgeManager()
|
||||
{
|
||||
var jm = judgeManager != null ? judgeManager : JudgeManager.Instance;
|
||||
if (jm != null)
|
||||
{
|
||||
try { jm.AllNotesJudged -= OnSettlementTriggered; } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSettlementTriggered()
|
||||
{
|
||||
// Disable animations when settlement begins
|
||||
if (animations != null)
|
||||
{
|
||||
try { animations.SetActive(false); }
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadBeatmap(Beatmap loadedBeatmap)
|
||||
{
|
||||
if (isSpawning) return;
|
||||
@@ -89,7 +193,9 @@ public class NoteSpawner : MonoBehaviour
|
||||
bpm = beatmap.bpm;
|
||||
startTime = Time.time;
|
||||
Debug.Log($"歌曲开始时间: {startTime}");
|
||||
StartCoroutine(SpawnNotes());
|
||||
|
||||
// keep reference so we can stop spawning when doing immediate settlement
|
||||
spawnCoroutine = StartCoroutine(SpawnNotes());
|
||||
}
|
||||
|
||||
private IEnumerator SpawnNotes()
|
||||
@@ -101,8 +207,14 @@ public class NoteSpawner : MonoBehaviour
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (NoteData note in beatmap.notes)
|
||||
// iterate with index so we can map hold notes to generated ids
|
||||
for (int i = 0; i < beatmap.notes.Length; i++)
|
||||
{
|
||||
// 允许外部在运行中打断生成(例如“立刻结算”)
|
||||
if (!isSpawning)
|
||||
yield break;
|
||||
|
||||
NoteData note = beatmap.notes[i];
|
||||
// clamp speed multiplier to supported range
|
||||
float sm = Mathf.Clamp(speedMultiplier, SpeedMultiplierMin, SpeedMultiplierMax);
|
||||
|
||||
@@ -128,7 +240,9 @@ public class NoteSpawner : MonoBehaviour
|
||||
|
||||
if (note.type == "hold")
|
||||
{
|
||||
SpawnHoldNote(note);
|
||||
// create the hold note once and record its id mapping
|
||||
int hid = SpawnHoldNote(note);
|
||||
noteIndexToHoldId[i] = hid;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -137,6 +251,110 @@ public class NoteSpawner : MonoBehaviour
|
||||
}
|
||||
|
||||
isSpawning = false;
|
||||
spawnCoroutine = null;
|
||||
|
||||
// Notify subscribers that all notes have been spawned
|
||||
AllNotesSpawned?.Invoke();
|
||||
|
||||
// Settlement routine will be started by GameManager via StartSettlementRoutine() call
|
||||
// after receiving the AllNotesSpawned event
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 立刻结算:
|
||||
/// - 停止继续生成音符(停止 SpawnNotes 协程)
|
||||
/// - 取消 NoteSpawner 自己的延迟结算协程(PostSpawnSettlementRoutine)
|
||||
/// - 立刻触发结算流程(JudgeManager.TriggerAllNotesJudged)
|
||||
/// 注意:该方法不会清理场上已生成的音符,仅停止后续生成并进入结算。
|
||||
/// </summary>
|
||||
[ContextMenu("Force Immediate Settlement")]
|
||||
public void ForceImmediateSettlement()
|
||||
{
|
||||
if (immediateSettlementTriggered)
|
||||
{
|
||||
Debug.LogWarning("[NoteSpawner] ForceImmediateSettlement ignored: already triggered.");
|
||||
return;
|
||||
}
|
||||
immediateSettlementTriggered = true;
|
||||
|
||||
Debug.LogWarning("[NoteSpawner] ForceImmediateSettlement called: stopping further note spawning and triggering settlement now.");
|
||||
|
||||
// If a pause UI is assigned, disable it immediately to avoid stuck paused UI during settlement
|
||||
if (pausePanel != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
pausePanel.SetActive(false);
|
||||
Debug.Log("[NoteSpawner] pausePanel has been disabled by immediate settlement.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning("[NoteSpawner] Failed to disable pausePanel: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Also disable animations if assigned
|
||||
if (animations != null)
|
||||
{
|
||||
try { animations.SetActive(false); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Restore pause manager state if present, otherwise fallback to setting timeScale
|
||||
try
|
||||
{
|
||||
var pm = PauseManager.Instance;
|
||||
if (pm != null)
|
||||
{
|
||||
pm.Pause(false);
|
||||
if (GameConfig.verboseLogs) Debug.Log("[NoteSpawner] PauseManager.Pause(false) called to resume time.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Time.timeScale = 1f;
|
||||
if (GameConfig.verboseLogs) Debug.Log("[NoteSpawner] PauseManager not found; Time.timeScale set to 1 as fallback.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try { Time.timeScale = 1f; } catch { }
|
||||
Debug.LogWarning("[NoteSpawner] Exception while restoring time scale: " + ex.Message);
|
||||
}
|
||||
|
||||
// stop spawning loop
|
||||
isSpawning = false;
|
||||
|
||||
// cancel spawn coroutine
|
||||
if (spawnCoroutine != null)
|
||||
{
|
||||
try { StopCoroutine(spawnCoroutine); } catch { }
|
||||
spawnCoroutine = null;
|
||||
}
|
||||
|
||||
// cancel delayed settlement coroutine if any
|
||||
if (settlementCoroutine != null)
|
||||
{
|
||||
try { StopCoroutine(settlementCoroutine); } catch { }
|
||||
settlementCoroutine = null;
|
||||
}
|
||||
|
||||
// Disable animations when settlement begins
|
||||
if (animations != null)
|
||||
{
|
||||
try { animations.SetActive(false); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
// trigger settlement
|
||||
var jm = judgeManager != null ? judgeManager : JudgeManager.Instance;
|
||||
if (jm != null)
|
||||
{
|
||||
jm.TriggerAllNotesJudged();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[NoteSpawner] ForceImmediateSettlement failed: JudgeManager reference missing.");
|
||||
}
|
||||
}
|
||||
|
||||
// 生成短音符
|
||||
@@ -217,25 +435,26 @@ public class NoteSpawner : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnHoldNote(NoteData noteData)
|
||||
// Modified: return generated holdNoteId so callers can map notes to ids
|
||||
public int SpawnHoldNote(NoteData noteData)
|
||||
{
|
||||
if (noteData.trackIndex < 0 || noteData.trackIndex >= spawnPoints.Length)
|
||||
{
|
||||
Debug.LogError("轨道索引超出范围!");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
KeyCode key = KeyBindingManager.GetKeyForColor(noteData.color);
|
||||
if (key == KeyCode.None)
|
||||
{
|
||||
Debug.LogError($"未找到颜色 {noteData.color} 对应的按键!");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(noteData.color))
|
||||
{
|
||||
Debug.LogError("[NoteSpawner] noteData.color 为空,无法生成音符!");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Debug.Log($"生成时间:{Time.time}");
|
||||
@@ -271,19 +490,11 @@ public class NoteSpawner : MonoBehaviour
|
||||
if (startObj == null)
|
||||
{
|
||||
Debug.LogError("对象池返回空 hold note start!");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// compute per-segment compensation only if enabled
|
||||
float startYOffset = 0f;
|
||||
if (enableYOffsetCompensation)
|
||||
{
|
||||
float startActivation = baseHit - effectiveTravelTimeHold;
|
||||
float timeSinceActivation = Time.time - startActivation;
|
||||
startYOffset = Mathf.Max(0f, timeSinceActivation * holdSpeed);
|
||||
}
|
||||
|
||||
startObj.transform.position = spawnPoint.position + Vector3.down * startYOffset;
|
||||
// Hold segments use absolute positioning; spawn at the lane origin.
|
||||
startObj.transform.position = spawnPoint.position;
|
||||
startObj.transform.rotation = Quaternion.identity;
|
||||
|
||||
HoldNote holdNote = startObj.GetComponent<HoldNote>();
|
||||
@@ -301,7 +512,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
else
|
||||
{
|
||||
Debug.LogError("长音符 start 部分缺少 HoldNote 组件!");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 生成 Middle 片段(1 .. segmentCount-1)
|
||||
@@ -317,16 +528,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
continue;
|
||||
}
|
||||
|
||||
float segYOffset = 0f;
|
||||
if (enableYOffsetCompensation)
|
||||
{
|
||||
float segHit = baseHit + segmentDelay;
|
||||
float segActivation = segHit - effectiveTravelTimeHold;
|
||||
float timeSinceActivationSeg = Time.time - segActivation;
|
||||
segYOffset = Mathf.Max(0f, timeSinceActivationSeg * holdSpeed);
|
||||
}
|
||||
|
||||
segObj.transform.position = spawnPoint.position + Vector3.down * segYOffset;
|
||||
segObj.transform.position = spawnPoint.position;
|
||||
segObj.transform.rotation = Quaternion.identity;
|
||||
|
||||
HoldNote holdSeg = segObj.GetComponent<HoldNote>();
|
||||
@@ -341,7 +543,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
holdSeg.visualSpeedMultiplier = smLocalHold;
|
||||
|
||||
// Immediately calibrate position and schedule additional checks to correct any offset
|
||||
Vector3 calibSpawnPos = spawnPoint.position + Vector3.down * segYOffset;
|
||||
Vector3 calibSpawnPos = spawnPoint.position;
|
||||
holdSeg.CalibratePosition(calibSpawnPos, calibrateTolerance);
|
||||
StartCoroutine(CalibrateAfterSpawn(holdSeg, calibSpawnPos));
|
||||
}
|
||||
@@ -356,21 +558,12 @@ public class NoteSpawner : MonoBehaviour
|
||||
if (endObj == null)
|
||||
{
|
||||
Debug.LogError("对象池返回空 hold note 片段(end)!");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
float endDelay = segmentCount * actualSegmentInterval; // 不按 speedMultiplier 缩放,使用谱面长度保证尾段紧随中段
|
||||
|
||||
float endYOffset = 0f;
|
||||
if (enableYOffsetCompensation)
|
||||
{
|
||||
float endHit = baseHit + endDelay;
|
||||
float endActivation = endHit - effectiveTravelTimeHold;
|
||||
float timeSinceActivationEnd = Time.time - endActivation;
|
||||
endYOffset = Mathf.Max(0f, timeSinceActivationEnd * holdSpeed);
|
||||
}
|
||||
|
||||
endObj.transform.position = spawnPoint.position + Vector3.down * endYOffset;
|
||||
endObj.transform.position = spawnPoint.position;
|
||||
endObj.transform.rotation = Quaternion.identity;
|
||||
|
||||
// 为便于识别,将实例名追加后缀
|
||||
@@ -389,7 +582,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
holdEnd.visualSpeedMultiplier = smLocalHold;
|
||||
|
||||
// schedule calibration for end as well to be safe
|
||||
Vector3 calibEndPos = spawnPoint.position + Vector3.down * endYOffset;
|
||||
Vector3 calibEndPos = spawnPoint.position;
|
||||
holdEnd.CalibratePosition(calibEndPos, calibrateTolerance);
|
||||
StartCoroutine(CalibrateAfterSpawn(holdEnd, calibEndPos));
|
||||
}
|
||||
@@ -397,6 +590,8 @@ public class NoteSpawner : MonoBehaviour
|
||||
{
|
||||
Debug.LogError("长音符 end 部分缺少 HoldNote 组件!");
|
||||
}
|
||||
|
||||
return holdNoteId;
|
||||
}
|
||||
|
||||
private IEnumerator CalibrateAfterSpawn(HoldNote seg, Vector3 spawnPos)
|
||||
@@ -440,6 +635,206 @@ public class NoteSpawner : MonoBehaviour
|
||||
return 10.75f / noteTravelTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public method to start the settlement routine. Called by GameManager when all notes have been spawned.
|
||||
/// </summary>
|
||||
public void StartSettlementRoutine()
|
||||
{
|
||||
if (GameConfig.verboseLogs) Debug.Log("[NoteSpawner] StartSettlementRoutine called - beginning settlement countdown");
|
||||
// keep reference so it can be cancelled by ForceImmediateSettlement
|
||||
if (settlementCoroutine != null) StopCoroutine(settlementCoroutine);
|
||||
settlementCoroutine = StartCoroutine(PostSpawnSettlementRoutine(5));
|
||||
}
|
||||
|
||||
private IEnumerator PostSpawnSettlementRoutine(int lookback)
|
||||
{
|
||||
// Get relevant notes: last notes within 3 seconds before the last note time
|
||||
if (beatmap == null || beatmap.notes == null || beatmap.notes.Length == 0)
|
||||
yield break;
|
||||
|
||||
NoteData lastNote = beatmap.notes[beatmap.notes.Length - 1];
|
||||
float lastNoteTime = lastNote.time;
|
||||
float timeRangeStart = lastNoteTime - 3f; // 3 seconds window instead of 0.5 seconds
|
||||
|
||||
// Collect notes within the range [timeRangeStart, lastNoteTime]
|
||||
List<NoteData> relevantNotes = new List<NoteData>();
|
||||
for (int i = beatmap.notes.Length - 1; i >= 0; i--)
|
||||
{
|
||||
NoteData note = beatmap.notes[i];
|
||||
if (note.time >= timeRangeStart)
|
||||
{
|
||||
relevantNotes.Add(note);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse to process in chronological order
|
||||
relevantNotes.Reverse();
|
||||
|
||||
if (GameConfig.verboseLogs) Debug.Log($"[NoteSpawner] Found {relevantNotes.Count} relevant notes in range [{timeRangeStart:F3}, {lastNoteTime:F3}]");
|
||||
|
||||
// Analyze notes: check if any are hold notes and find the latest ending note
|
||||
bool hasHoldNotes = false;
|
||||
float maxEndTime = float.MinValue;
|
||||
NoteData maxEndNote = null;
|
||||
|
||||
foreach (var note in relevantNotes)
|
||||
{
|
||||
float noteEndTime;
|
||||
if (note.type == "hold")
|
||||
{
|
||||
hasHoldNotes = true;
|
||||
noteEndTime = note.time + note.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
noteEndTime = note.time;
|
||||
}
|
||||
|
||||
if (noteEndTime > maxEndTime)
|
||||
{
|
||||
maxEndTime = noteEndTime;
|
||||
maxEndNote = note;
|
||||
}
|
||||
|
||||
if (GameConfig.verboseLogs)
|
||||
{
|
||||
Debug.Log($"[NoteSpawner] Note: type={note.type}, time={note.time:F3}, endTime={noteEndTime:F3}");
|
||||
}
|
||||
}
|
||||
|
||||
// Determine initial wait and type of max end note
|
||||
float initialWait = 0f;
|
||||
bool maxIsHold = false;
|
||||
|
||||
if (maxEndNote != null)
|
||||
{
|
||||
if (maxEndNote.type == "hold")
|
||||
{
|
||||
maxIsHold = true;
|
||||
initialWait = maxEndNote.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxIsHold = false;
|
||||
initialWait = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (GameConfig.verboseLogs)
|
||||
{
|
||||
Debug.Log($"[NoteSpawner] Max end note: type={maxEndNote?.type}, time={maxEndNote?.time:F3}, maxIsHold={maxIsHold}, initialWait={initialWait:F3}");
|
||||
}
|
||||
|
||||
// Log final chosen extension method and total extension (initial wait + final buffer) as an error for visibility
|
||||
float finalBuffer = 3f; // final buffer used by settlement routine (changed to 3s)
|
||||
float totalWait = initialWait + finalBuffer;
|
||||
string methodName = maxIsHold ? "hold" : "tap";
|
||||
Debug.LogError($"[NoteSpawner] Settlement extension chosen: method={methodName}, initialWait={initialWait:F3}s, finalBuffer={finalBuffer:F3}s, totalWait={totalWait:F3}s");
|
||||
|
||||
// Clear the reference list to release memory after use
|
||||
relevantNotes.Clear();
|
||||
relevantNotes = null;
|
||||
|
||||
// Wait for initial period (hold length or 0)
|
||||
if (initialWait > 0f)
|
||||
{
|
||||
if (GameConfig.verboseLogs) Debug.Log($"[NoteSpawner] Waiting for initial hold length: {initialWait:F3}s");
|
||||
float target = Time.time + initialWait;
|
||||
while (Time.time < target)
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Final buffer: use finalBuffer variable
|
||||
if (GameConfig.verboseLogs) Debug.Log($"[NoteSpawner] Entering final {finalBuffer} s settlement buffer");
|
||||
|
||||
// Wait until 1s remaining, then clear input (clear at finalBuffer-1 seconds mark)
|
||||
float timeBeforeClear = Mathf.Max(0f, finalBuffer - 1f);
|
||||
if (timeBeforeClear > 0f)
|
||||
{
|
||||
float tBefore = Time.time + timeBeforeClear;
|
||||
while (Time.time < tBefore)
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Force clear keyboard/input state at the 1s-before-end mark
|
||||
ForceClearInputState(null);
|
||||
|
||||
// Wait the remaining 1s
|
||||
float tAfter = Time.time + 1f;
|
||||
while (Time.time < tAfter)
|
||||
yield return null;
|
||||
|
||||
// Trigger settlement
|
||||
try
|
||||
{
|
||||
if (JudgeManager.Instance != null)
|
||||
{
|
||||
JudgeManager.Instance.OnAllNotesJudged();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[NoteSpawner] JudgeManager.Instance is null when trying to trigger settlement");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning("[NoteSpawner] Exception while triggering settlement: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ForceClearInputState(List<NoteData> relevantNotes)
|
||||
{
|
||||
// Fire UI key release handlers: reset InputManager key indicator colors
|
||||
var im = InputManager.Instance;
|
||||
if (im != null)
|
||||
{
|
||||
var texts = im.trackKeyTexts;
|
||||
if (texts != null)
|
||||
{
|
||||
for (int ti = 0; ti < texts.Length; ti++)
|
||||
{
|
||||
if (texts[ti] != null)
|
||||
texts[ti].color = im.keyInactiveColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset per-frame consumption and unlock any track locks
|
||||
if (TrackKeyManager.Instance != null)
|
||||
{
|
||||
TrackKeyManager.Instance.ResetConsumptionState();
|
||||
TrackKeyManager.Instance.ClearAllLocks();
|
||||
if (GameConfig.verboseLogs) Debug.Log("[NoteSpawner] TrackKeyManager consumption state reset and locks cleared");
|
||||
}
|
||||
|
||||
// Mark all relevant hold notes as released in JudgeManager
|
||||
// Only process if relevantNotes is provided (non-null)
|
||||
if (relevantNotes != null && JudgeManager.Instance != null && beatmap != null && beatmap.notes != null)
|
||||
{
|
||||
foreach (var note in relevantNotes)
|
||||
{
|
||||
if (note == null) continue;
|
||||
if (note.type == "hold")
|
||||
{
|
||||
// Find the index of this note in beatmap to get its hold ID
|
||||
for (int i = 0; i < beatmap.notes.Length; i++)
|
||||
{
|
||||
if (beatmap.notes[i] == note && noteIndexToHoldId.ContainsKey(i))
|
||||
{
|
||||
int holdId = noteIndexToHoldId[i];
|
||||
try { JudgeManager.Instance.RegisterNoteReleased(holdId.ToString(), true); }
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
//if (globalGameTime.text=="0.01")
|
||||
|
||||
Reference in New Issue
Block a user