feat: polish VR gameplay and sync tools
This commit is contained in:
@@ -19,16 +19,25 @@ public class SongController : MonoBehaviour
|
||||
private const float VerticalCenter = 1f;
|
||||
|
||||
private AudioManager _audio;
|
||||
private ScoreManager _scoreManager;
|
||||
private float _clipLength;
|
||||
|
||||
private static string CacheRoot =>
|
||||
Path.Combine(Application.temporaryCachePath, "beatsaber");
|
||||
Path.Combine(Application.persistentDataPath, "beatsaber");
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_audio = FindFirstObjectByType<AudioManager>();
|
||||
_scoreManager = FindFirstObjectByType<ScoreManager>();
|
||||
StartCoroutine(LoadAndPlay());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_audio != null && _scoreManager != null && _clipLength > 0.0f)
|
||||
_scoreManager.SetSongProgress(_audio.CurrentTime, _clipLength);
|
||||
}
|
||||
|
||||
private IEnumerator LoadAndPlay()
|
||||
{
|
||||
SongInfo song = GameSession.SelectedSong;
|
||||
@@ -53,6 +62,7 @@ public class SongController : MonoBehaviour
|
||||
}
|
||||
clip = DownloadHandlerAudioClip.GetContent(req);
|
||||
}
|
||||
_clipLength = clip.length;
|
||||
|
||||
// Load and parse map
|
||||
DifficultyInfo diffInfo = song.difficulties.Get(diff);
|
||||
@@ -74,13 +84,14 @@ public class SongController : MonoBehaviour
|
||||
yield break;
|
||||
}
|
||||
map.target.Sort(CompareNotes);
|
||||
_scoreManager?.SetTotalNotes(map.target.Count);
|
||||
|
||||
yield return StartCoroutine(Countdown());
|
||||
|
||||
_audio.PlayClip(clip);
|
||||
|
||||
StartCoroutine(SpawnRoutine(map.target));
|
||||
yield return StartCoroutine(WaitForCompletion(clip.length));
|
||||
yield return StartCoroutine(WaitForCompletion(clip.length, map.target));
|
||||
}
|
||||
|
||||
private IEnumerator Countdown()
|
||||
@@ -106,7 +117,8 @@ public class SongController : MonoBehaviour
|
||||
|
||||
foreach (NoteData note in notes)
|
||||
{
|
||||
float spawnAt = Mathf.Max(0f, note.time - travelTime);
|
||||
float adjustedNoteTime = note.time + GlobalSyncSettings.AudioOffsetSeconds;
|
||||
float spawnAt = Mathf.Max(0f, adjustedNoteTime - travelTime);
|
||||
yield return new WaitUntil(() => _audio.CurrentTime >= spawnAt);
|
||||
SpawnNote(note);
|
||||
}
|
||||
@@ -118,7 +130,7 @@ public class SongController : MonoBehaviour
|
||||
float y = MapLayerY(note.lineLayer);
|
||||
|
||||
// 스폰 시점의 실제 남은 시간으로 역산 → 동시 노트가 프레임 차이 나도 같은 타이밍에 도착
|
||||
float remaining = note.time - _audio.CurrentTime;
|
||||
float remaining = note.time + GlobalSyncSettings.AudioOffsetSeconds - _audio.CurrentTime;
|
||||
float travelTime = Mathf.Max(0.05f, remaining);
|
||||
|
||||
var info = new SpawnEventInfo
|
||||
@@ -126,7 +138,7 @@ public class SongController : MonoBehaviour
|
||||
position = new Vector3(x, y, 0f),
|
||||
colorSide = note.colorType == 0 ? ColorSide.Left : ColorSide.Right,
|
||||
hitDirection = MapCutDirection(note.cutDirection),
|
||||
useSpark = true,
|
||||
useSpark = false,
|
||||
speed = 2f,
|
||||
travelTimeOverride = travelTime,
|
||||
};
|
||||
@@ -177,9 +189,13 @@ public class SongController : MonoBehaviour
|
||||
private static Direction MapCutDirection(int cut)
|
||||
=> (cut >= 0 && cut < CutDirMap.Length) ? CutDirMap[cut] : Direction.Center;
|
||||
|
||||
private IEnumerator WaitForCompletion(float clipLength)
|
||||
private IEnumerator WaitForCompletion(float clipLength, List<NoteData> notes)
|
||||
{
|
||||
yield return new WaitUntil(() => _audio.CurrentTime >= clipLength - 0.5f);
|
||||
float lastNoteTime = notes.Count > 0 ? notes[notes.Count - 1].time : 0.0f;
|
||||
float resultTime = Mathf.Min(clipLength, lastNoteTime + GlobalSyncSettings.AudioOffsetSeconds + 0.35f);
|
||||
yield return new WaitUntil(() => _audio.CurrentTime >= resultTime);
|
||||
yield return new WaitForSeconds(0.35f);
|
||||
_scoreManager?.CompleteSong();
|
||||
onLevelComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user