From 1e0483f210bff1f9ee4a54074ae61a8e936b0d1d Mon Sep 17 00:00:00 2001 From: nakjun Date: Fri, 12 Jun 2026 14:57:38 +0900 Subject: [PATCH] =?UTF-8?q?2026-06-12=20=EB=85=B8=ED=8A=B8=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WhaleAdventure_VR/Rooms/CatsRoom.unity | 4 +- Assets/02_Scripts/Data/Rhythm/RhythmChart.cs | 2 +- .../Managers/CatsRoom/RhythmManager.cs | 38 +++++++++++++++- .../02_Scripts/Rhythm/RhythmNoteInstance.cs | 43 +++++++++++++++++-- Assets/02_Scripts/Rhythm/RhythmNoteSpawner.cs | 17 ++++++-- Assets/04_Models/Note/Prefabs/Note.prefab | 4 +- 6 files changed, 93 insertions(+), 15 deletions(-) diff --git a/Assets/01_Scenes/WhaleAdventure_VR/Rooms/CatsRoom.unity b/Assets/01_Scenes/WhaleAdventure_VR/Rooms/CatsRoom.unity index 2fd4d4f5..6c75862e 100644 --- a/Assets/01_Scenes/WhaleAdventure_VR/Rooms/CatsRoom.unity +++ b/Assets/01_Scenes/WhaleAdventure_VR/Rooms/CatsRoom.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:303e9b484d924db4bc80c015aa378697af473fb17b3c3b1473529b42995fcdb4 -size 1997728 +oid sha256:4a3b7ee744abcb11b1e2c6a938803a3046f364f4a8b885673c2b601559a2d5f4 +size 1997429 diff --git a/Assets/02_Scripts/Data/Rhythm/RhythmChart.cs b/Assets/02_Scripts/Data/Rhythm/RhythmChart.cs index ebdb5f9a..3875b3ed 100644 --- a/Assets/02_Scripts/Data/Rhythm/RhythmChart.cs +++ b/Assets/02_Scripts/Data/Rhythm/RhythmChart.cs @@ -3,7 +3,7 @@ public class Note { - public float Time; + [HideInInspector] public float Time; } [CreateAssetMenu(fileName = "RhythmChart", menuName = "CatsRoom/RhythmChart")] diff --git a/Assets/02_Scripts/Managers/CatsRoom/RhythmManager.cs b/Assets/02_Scripts/Managers/CatsRoom/RhythmManager.cs index b292035b..a707f85f 100644 --- a/Assets/02_Scripts/Managers/CatsRoom/RhythmManager.cs +++ b/Assets/02_Scripts/Managers/CatsRoom/RhythmManager.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using UnityEngine; @@ -6,10 +7,19 @@ public class RhythmManager : MonoBehaviour { [SerializeField] private AudioSource _audioSource; [SerializeField] private RhythmChart _currentChart; - private float SongTime => _audioSource.time; // 모든 타이밍의 기준 + [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() { @@ -22,6 +32,23 @@ 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++; } } @@ -34,6 +61,7 @@ public void ChangeSong() public void StartSong() { SongNoteList = _currentChart.GenerateNotes(); + _nextNoteIndex = 0; _audioSource.Play(); _isPlaying = true; @@ -51,9 +79,15 @@ public void StopSong() if (SoundManager.Instance != null) SoundManager.Instance.ExitMinigameMode(); } + // 노트가 판정선을 지나쳐 스스로 Miss 처리될 때 호출 + private void OnNoteMissed(RhythmNoteInstance note) + { + // TODO: 점수/콤보 시스템 연결 시 Miss 반영 + } + public void OnPlayerInput() { - + } public Result Judge(float diff) diff --git a/Assets/02_Scripts/Rhythm/RhythmNoteInstance.cs b/Assets/02_Scripts/Rhythm/RhythmNoteInstance.cs index d9caf8be..b75f6d57 100644 --- a/Assets/02_Scripts/Rhythm/RhythmNoteInstance.cs +++ b/Assets/02_Scripts/Rhythm/RhythmNoteInstance.cs @@ -1,12 +1,47 @@ +using System; using UnityEngine; public class RhythmNoteInstance : MonoBehaviour { - public float HitTime; // 이 노트의 도달 시각 - + public float HitTime; // 이 노트의 도달 시각 + + [SerializeField] private float _missWindow = 0.15f; // 판정선을 이만큼 지나면 자동 Miss + + private Vector3 _start; // 출발점 + private Vector3 _target; // 목적지(판정선) + private float _spawnTime; // 생성된 시각 (= HitTime - leadTime) + private Func _songTime; // 오디오 기준 현재 곡 시간 제공자 + private Action _onMiss; // 지나쳐서 Miss 났을 때 통지 + + // 스폰 시 목적지·타이밍 주입 (B 방식) + public void Setup(Vector3 start, Vector3 target, float spawnTime, float hitTime, + Func songTime, Action onMiss = null) + { + _start = start; + _target = target; + _spawnTime = spawnTime; + HitTime = hitTime; + _songTime = songTime; + _onMiss = onMiss; + + transform.position = start; + } + private void Update() { - // 판정선 향해 이동 - // 너무 지나가면 Miss 처리 후 자기 파괴 + if (_songTime == null) return; + + float now = _songTime(); + + // SongTime 기반 보간: spawnTime → HitTime 구간을 0→1로 + float t = Mathf.InverseLerp(_spawnTime, HitTime, now); + transform.position = Vector3.LerpUnclamped(_start, _target, t); + + // 판정선을 missWindow 이상 지나치면 Miss 처리 후 자기 파괴 + if (now > HitTime + _missWindow) + { + _onMiss?.Invoke(this); + Destroy(gameObject); + } } } diff --git a/Assets/02_Scripts/Rhythm/RhythmNoteSpawner.cs b/Assets/02_Scripts/Rhythm/RhythmNoteSpawner.cs index da2ac86f..721b6e9d 100644 --- a/Assets/02_Scripts/Rhythm/RhythmNoteSpawner.cs +++ b/Assets/02_Scripts/Rhythm/RhythmNoteSpawner.cs @@ -1,10 +1,19 @@ +using System; using UnityEngine; public class RhythmNoteSpawner : MonoBehaviour { - // 노트 프리팹 생성, 도달시간 주입 - public void SpawnNote(Note note) + [SerializeField] private RhythmNoteInstance _notePrefab; // 생성할 노트 프리팹 + [SerializeField] private Transform _spawnPoint; // 노트가 생겨나는 위치(미지정 시 자기 위치) + [SerializeField] private Transform _judgmentLine; // 목적지(판정선) + + // 노트 프리팹 생성, 목적지·타이밍 주입 + public RhythmNoteInstance SpawnNote(Note note, float spawnTime, + Func songTime, Action onMiss = null) { - - } + Transform origin = _spawnPoint != null ? _spawnPoint : transform; + RhythmNoteInstance instance = Instantiate(_notePrefab, origin.position, origin.rotation, transform); + instance.Setup(origin.position, _judgmentLine.position, spawnTime, note.Time, songTime, onMiss); + return instance; + } } diff --git a/Assets/04_Models/Note/Prefabs/Note.prefab b/Assets/04_Models/Note/Prefabs/Note.prefab index 4e6616cd..15e0f2a2 100644 --- a/Assets/04_Models/Note/Prefabs/Note.prefab +++ b/Assets/04_Models/Note/Prefabs/Note.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:624f2b164c4ccf21e4c3a915b31f999e27178ada6f622fa88abcc852688552e1 -size 901 +oid sha256:d84b6d4eacebbeab97aa0a0e1e6f05a4b0dd9be7283d897f621612f43275d3cd +size 4578