hold音符补丁 备份

This commit is contained in:
2026-03-03 14:07:39 +08:00
parent b8704629a3
commit 9011fa022e
36 changed files with 2721 additions and 256 deletions
@@ -27,6 +27,12 @@ public class NoteSpawner : MonoBehaviour
[Tooltip("Global additional realtime offset (seconds) added to hit times for all notes. Use to test input latency or adjust judgement timing. Default 0. Can be negative to make notes arrive earlier.")]
public float globalHitDelay = 0f;
[Header("Sync Note Detection")]
[Tooltip("Whether to spawn a special prefab for notes that appear within 0.05s of each other.")]
public bool enableSyncNotePrefab = false;
[Tooltip("The prefab to instantiate under the note when a sync is detected.")]
public GameObject syncNotePrefab;
// Documentation text normalized.
[Tooltip("Multiplier applied to visual fall speed. Changing this will automatically adjust spawn timing so notes still arrive at their original beat times.")]
[Range(0.5f, 2f)]
@@ -131,6 +137,10 @@ public class NoteSpawner : MonoBehaviour
spawnOffset = savedDelay + static_value_add_to_spawnoffset;
if (JudgeManager.IsDebugEnabled) Debug.Log($"[NoteSpawner] Applied spawnOffset={spawnOffset} (Saved={savedDelay} + Static={static_value_add_to_spawnoffset})");
// 读取 PlayerPrefs 中的同步音符开关状态
enableSyncNotePrefab = PlayerPrefs.GetInt("EnableSyncNotePrefab", 1) == 1;
if (JudgeManager.IsDebugEnabled) Debug.Log($"[NoteSpawner] Applied enableSyncNotePrefab={enableSyncNotePrefab}");
// restore animations active state on Start
if (animations != null)
{
@@ -254,6 +264,27 @@ public class NoteSpawner : MonoBehaviour
NoteData note = beatmap.notes[i];
// Check if this is a sync note (within 0.05s of any other note)
bool isSync = false;
if (enableSyncNotePrefab)
{
// Check previous notes (optimized assuming sorted beatmap)
for (int j = i - 1; j >= 0; j--)
{
if (Mathf.Abs(note.time - beatmap.notes[j].time) <= 0.05f) { isSync = true; break; }
if (note.time - beatmap.notes[j].time > 0.05f) break;
}
if (!isSync)
{
// Check next notes (optimized assuming sorted beatmap)
for (int j = i + 1; j < beatmap.notes.Length; j++)
{
if (Mathf.Abs(note.time - beatmap.notes[j].time) <= 0.05f) { isSync = true; break; }
if (beatmap.notes[j].time - note.time > 0.05f) break;
}
}
}
float travelTime = GetLaneTravelTimeSeconds(laneTravelTimes, note.trackIndex);
float spawnTime = note.time - travelTime;
float delay = spawnTime - (Time.time - startTime) + spawnOffset;
@@ -272,12 +303,12 @@ public class NoteSpawner : MonoBehaviour
if (note.type == "hold")
{
// create the hold note once and record its id mapping
int hid = SpawnHoldNote(note, sm, travelTime, noteSpeed, segmentInterval);
int hid = SpawnHoldNote(note, sm, travelTime, noteSpeed, segmentInterval, isSync);
noteIndexToHoldId[i] = hid;
}
else
{
SpawnNote(note, sm, travelTime, noteSpeed);
SpawnNote(note, sm, travelTime, noteSpeed, isSync);
}
}
@@ -299,7 +330,7 @@ public class NoteSpawner : MonoBehaviour
return key;
}
public void SpawnNote(NoteData noteData, float sm, float travelTime, float noteSpeed)
public void SpawnNote(NoteData noteData, float sm, float travelTime, float noteSpeed, bool isSync = false)
{
if (noteData.trackIndex < 0 || noteData.trackIndex >= spawnPoints.Length)
{
@@ -321,6 +352,23 @@ public class NoteSpawner : MonoBehaviour
return;
}
if (enableSyncNotePrefab && syncNotePrefab != null)
{
// Clean up any existing sync prefab from previous use in pool
foreach (Transform child in note.transform)
{
if (child.name.StartsWith(syncNotePrefab.name))
{
Destroy(child.gameObject);
}
}
if (isSync)
{
Instantiate(syncNotePrefab, note.transform);
}
}
Transform spawnPoint = spawnPoints[noteData.trackIndex];
// Calculate hit time (realtime when note should be judged)
@@ -354,7 +402,7 @@ public class NoteSpawner : MonoBehaviour
}
// Modified: return generated holdNoteId so callers can map notes to ids
public int SpawnHoldNote(NoteData noteData, float sm, float travelTime, float noteSpeed, float segmentInterval)
public int SpawnHoldNote(NoteData noteData, float sm, float travelTime, float noteSpeed, float segmentInterval, bool isSync = false)
{
if (noteData.trackIndex < 0 || noteData.trackIndex >= spawnPoints.Length)
{
@@ -398,6 +446,23 @@ public class NoteSpawner : MonoBehaviour
return -1;
}
if (enableSyncNotePrefab && syncNotePrefab != null)
{
// Clean up any existing sync prefab from previous use in pool
foreach (Transform child in startObj.transform)
{
if (child.name.StartsWith(syncNotePrefab.name))
{
Destroy(child.gameObject);
}
}
if (isSync)
{
Instantiate(syncNotePrefab, startObj.transform);
}
}
// Hold segments use absolute positioning; spawn at the lane origin.
startObj.transform.position = spawnPoint.position;
startObj.transform.rotation = Quaternion.identity;