using System; using System.Collections.Generic; using UnityEngine; public enum Result { Perfect, Good, Miss } public class RhythmManager : MonoBehaviour { [SerializeField] private AudioSource _audioSource; [SerializeField] private RhythmChart _currentChart; [SerializeField] private RhythmNoteSpawner _spawner; [SerializeField] private float _leadTime = 2f; // 노트가 생성돼 판정선까지 흐르는 시간(초) public float SongTime => _audioSource.time; // 모든 타이밍의 기준 private List SongNoteList; private int _nextNoteIndex; // 다음에 소환할 노트 인덱스 private bool _isPlaying; //곡이 재생 중인지 (종료 감지용) private Func _songTimeProvider; // 노트에 넘길 시간 제공자 (매 스폰마다 람다 재생성 방지용 캐시) private void Awake() { _songTimeProvider = () => SongTime; // 한 번만 만들어 모든 노트가 공유 } private void Start() { ChangeSong(); } private void Update() { //재생 중이던 곡이 끝나면 주변음 복구 if (_isPlaying && !_audioSource.isPlaying) { StopSong(); return; } if (_isPlaying) SpawnDueNotes(); } // SongTime 기준으로 소환할 때가 된 노트들을 순서대로 생성 private void SpawnDueNotes() { // 판정 시각보다 _leadTime 먼저 생성해야 박자에 맞춰 판정선에 도달 while (_nextNoteIndex < SongNoteList.Count && //총 노트수보다 노트인덱스가 작고 SongTime >= SongNoteList[_nextNoteIndex].Time - _leadTime) //노래길이가 다음 노트의 노트타임 - 리드타임 보다 작을때까지만 { Note note = SongNoteList[_nextNoteIndex]; // spawnTime은 실제 프레임 시각이 아니라 이론값(note.Time - _leadTime)으로 줘야 보간이 정확 _spawner.SpawnNote(note, note.Time - _leadTime, _songTimeProvider, OnNoteMissed); _nextNoteIndex++; } } public void ChangeSong() { _audioSource.clip = _currentChart.SongClip; } // 곡 재생 + 채보 로드 public void StartSong() { SongNoteList = _currentChart.GenerateNotes(); _nextNoteIndex = 0; _audioSource.Play(); _isPlaying = true; //BGM·환경음을 낮춰 리듬게임 소리만 들리게 if (SoundManager.Instance != null) SoundManager.Instance.EnterMinigameMode(); } // 곡 정지 + 주변음 복구 public void StopSong() { _audioSource.Stop(); _isPlaying = false; if (SoundManager.Instance != null) SoundManager.Instance.ExitMinigameMode(); } // 노트가 판정선을 지나쳐 스스로 Miss 처리될 때 호출 private void OnNoteMissed(RhythmNoteInstance note) { // TODO: 점수/콤보 시스템 연결 시 Miss 반영 } public void OnPlayerInput() { } public Result Judge(float diff) { return Result.Miss; } }