2026-06-18 많은 플레이어 수정사항
This commit is contained in:
@@ -25,12 +25,18 @@ public class RhythmManager : MonoBehaviour
|
||||
|
||||
[SerializeField] private GameObject StartButtonObj;
|
||||
|
||||
[Header("시작 카운트다운 (VR 준비 시간)")]
|
||||
[SerializeField] private float _countdownTime = 5f; // 시작 버튼 후 노래가 실제로 시작되기까지 대기 시간(초)
|
||||
[SerializeField] private AudioClip _countdownBeep; // 매초 카운트 효과음 (5,4,3,2,1)
|
||||
[SerializeField] private AudioClip _countdownGoSfx; // 카운트 끝(GO) 효과음 (선택)
|
||||
|
||||
// 모든 타이밍의 기준. 오디오 클럭(dspTime) 기반이라 리드인 동안 음수(-leadTime→0)로 흐른다
|
||||
public float SongTime => (float)(AudioSettings.dspTime - _dspSongStart);
|
||||
|
||||
private List<Note> SongNoteList;
|
||||
private int _nextNoteIndex; // 다음에 소환할 노트 인덱스
|
||||
private bool _isPlaying; //곡이 재생 중인지 (종료 감지용)
|
||||
private bool _isCountingDown; // 시작 카운트다운 진행 중 여부 (중복 클릭 방지용)
|
||||
private double _dspSongStart; // 오디오가 실제 시작되는 dsp 시각 (= SongTime 0 지점)
|
||||
private float _clipLength; // 곡 길이 캐시 (종료 감지용)
|
||||
private Func<float> _songTimeProvider; // 노트에 넘길 시간 제공자 (매 스폰마다 람다 재생성 방지용 캐시)
|
||||
@@ -44,6 +50,10 @@ public class RhythmManager : MonoBehaviour
|
||||
public event Action<RhythmScore> OnScoreChanged; // 점수/콤보가 바뀔 때 (실시간 HUD)
|
||||
public event Action<RhythmScore> OnSongFinished; // 곡이 끝났을 때 (결과창)
|
||||
|
||||
public event Action OnCountdownStarted; // 시작 버튼 직후 카운트다운 시작 (CountdownHud 표시)
|
||||
public event Action<int> OnCountdownTick; // 남은 초 (5,4,3,2,1) — 매초 호출
|
||||
public event Action OnCountdownFinished; // 카운트 종료(GO!) — 곡 시작 직전
|
||||
|
||||
private RhythmCat[] _rhythmCats;
|
||||
|
||||
private void Awake()
|
||||
@@ -151,8 +161,55 @@ public void ChangeSong()
|
||||
// 오토플레이 아이템 사용: 곡 시작 전(또는 도중)에 호출하면 남은 노트가 전부 자동 Perfect
|
||||
public void EnableAutoPlay() => _autoPlay = true;
|
||||
|
||||
// 곡 재생 + 채보 로드
|
||||
// 시작 버튼 핸들러: 곧장 시작하지 않고 VR 준비 시간(카운트다운) 후 BeginSong 호출
|
||||
public void StartSong()
|
||||
{
|
||||
if (_isPlaying) return; // 이미 재생 중이면 무시
|
||||
if (_isCountingDown) return; // 카운트다운 진행 중 중복 클릭 차단
|
||||
|
||||
if (StartButtonObj != null) StartButtonObj.SetActive(false); // 버튼 즉시 숨김
|
||||
_ = CountdownThenBeginAsync(); // fire-and-forget (await 결과 불필요)
|
||||
}
|
||||
|
||||
// 매초 비프음 + 남은 초 이벤트를 보내며 _countdownTime 만큼 대기한 뒤 곡 시작
|
||||
private async Awaitable CountdownThenBeginAsync()
|
||||
{
|
||||
_isCountingDown = true;
|
||||
try
|
||||
{
|
||||
OnCountdownStarted?.Invoke(); // CountdownHud 표시
|
||||
|
||||
int remaining = Mathf.Max(1, Mathf.CeilToInt(_countdownTime));
|
||||
while (remaining > 0)
|
||||
{
|
||||
OnCountdownTick?.Invoke(remaining); // 화면에 숫자 표시
|
||||
if (_countdownBeep != null && SoundManager.Instance != null)
|
||||
SoundManager.Instance.PlaySFX(_countdownBeep); // 매초 비프음
|
||||
|
||||
// destroyCancellationToken: 카운트다운 도중 오브젝트가 파괴되면 await가 취소돼
|
||||
// 파괴된 객체에서 BeginSong이 호출되는 걸 막는다
|
||||
await Awaitable.WaitForSecondsAsync(1f, destroyCancellationToken);
|
||||
remaining--;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return; // 파괴/취소 시 곡 시작하지 않고 종료
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isCountingDown = false;
|
||||
}
|
||||
|
||||
OnCountdownFinished?.Invoke(); // GO! 표시
|
||||
if (_countdownGoSfx != null && SoundManager.Instance != null)
|
||||
SoundManager.Instance.PlaySFX(_countdownGoSfx);
|
||||
|
||||
BeginSong();
|
||||
}
|
||||
|
||||
// 곡 재생 + 채보 로드 (카운트다운 종료 후 실제 시작)
|
||||
private void BeginSong()
|
||||
{
|
||||
SongNoteList = _currentChart.GenerateNotes();
|
||||
_nextNoteIndex = 0;
|
||||
@@ -161,7 +218,6 @@ public void StartSong()
|
||||
Score.Reset();
|
||||
OnSongStarted?.Invoke(); // ScoreHud 표시 / ResultHud 숨김
|
||||
OnScoreChanged?.Invoke(Score); // HUD 초기화(0점)
|
||||
StartButtonObj.SetActive(false);
|
||||
|
||||
_clipLength = _audioSource.clip != null ? _audioSource.clip.length : 0f;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user