diff --git a/Assets/01_Scenes/Festival_Chapter5.unity b/Assets/01_Scenes/Festival_Chapter5.unity index d41671f7..b86cf3cd 100644 --- a/Assets/01_Scenes/Festival_Chapter5.unity +++ b/Assets/01_Scenes/Festival_Chapter5.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc6508913ab354d604980a3b0ef749c10b8152edb1e91446f5745f991fa41447 -size 1629262 +oid sha256:64d836f31368bb50449f1c1d92cd281af71df172e8153a90d202ad98bc6b0bd7 +size 1631753 diff --git a/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs b/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs index d3d5e49c..7c21aa18 100644 --- a/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs +++ b/Assets/02_Scripts/Communication/Dialog/DialogPlayer.cs @@ -23,6 +23,10 @@ public struct DialogEntry [Tooltip("대화 선택 메뉴에 표시할 이름 (비우면 그룹 이름 사용)")] public string MenuLabel; + + [Tooltip("켜면 이 대화에선 말을 걸어도 플레이어 쪽으로 회전하지 않는다 (기본: 회전함). " + + "정면을 고정한 연출 대화 등에 사용. 단, 선택 메뉴가 뜨는 다중 대화에선 메뉴를 위해 회전할 수 있음")] + public bool DontRotateToPlayer; } // 노드의 EventKey ↔ 그 노드 재생 시 호출할 이벤트. @@ -130,8 +134,15 @@ public async Awaitable Play() // 말을 걸면 NPC가 플레이어 쪽으로 돌아본다 — 대화창(선택 메뉴·첫 대사)이 NPC 회전을 // 따라가므로 창도 플레이어를 향하게 된다. 원래 회전은 아래 finally에서 복원. - _originalRotations.TryAdd(transform, GetOriginalRotation(transform)); - RotateTowardPlayer(transform); + // 단, 대화 항목이 하나이고 그 항목이 DontRotateToPlayer면 회전하지 않는다(정면 고정 연출 등). + // 여러 개(선택 메뉴)일 땐 메뉴가 플레이어를 향하도록 우선 회전한다. + bool singleEntry = playable.Count == 1; + bool rotateToPlayer = !singleEntry || !_dialogs[playable[0]].DontRotateToPlayer; + if (rotateToPlayer) + { + _originalRotations.TryAdd(transform, GetOriginalRotation(transform)); + RotateTowardPlayer(transform); + } // 대화창이 바로 튀어나오지 않도록 잠깐 뜸을 들인다 (선택 메뉴·첫 대사 공통) if (_dialogStartDelay > 0f) @@ -140,7 +151,7 @@ public async Awaitable Play() if (_entryInProgress != null) return; // 기다리는 사이 다른 NPC의 대화가 시작됨 } - int index = playable.Count == 1 ? playable[0] : await SelectDialog(playable); + int index = singleEntry ? playable[0] : await SelectDialog(playable); if (index < 0) return; // 선택 대기 중 취소됨 (다른 NPC와 대화 시작, 씬 전환 등) _entryInProgress = this; // 여기서부터 실제 대사 재생 — 끝날 때까지 다른 NPC 상호작용 무시 @@ -187,8 +198,11 @@ private async Awaitable PlayGroupForced(DialogGroup group) if (entry.Group == null) entry = new DialogEntry { Group = group }; - _originalRotations.TryAdd(transform, GetOriginalRotation(transform)); - RotateTowardPlayer(transform); + if (!entry.DontRotateToPlayer) + { + _originalRotations.TryAdd(transform, GetOriginalRotation(transform)); + RotateTowardPlayer(transform); + } if (_dialogStartDelay > 0f) { diff --git a/Assets/02_Scripts/Managers/LocalManager.cs b/Assets/02_Scripts/Managers/LocalManager.cs index adc7eb58..de636bf5 100644 --- a/Assets/02_Scripts/Managers/LocalManager.cs +++ b/Assets/02_Scripts/Managers/LocalManager.cs @@ -22,6 +22,11 @@ public class LocalManager : MonoBehaviour,ISceneInitializable // 이 씬 전용 스카이박스 (비우면 SceneLoadManager의 기본 스카이박스 사용) [SerializeField] private Material _sceneSkybox; + // FadeToGrayscale 직전의 원래 볼륨 상태 — FadeToColor로 되돌릴 때 복원용 + private VolumeProfile _preGrayscaleProfile; + private float _preGrayscaleWeight; + private bool _grayscaleActive; + public void NextScene(int delay) { _ = Util.RunDelayed((float)delay,()=>SceneLoadManager.Instance.RequestSceneChange(_nextSceneName)); @@ -72,7 +77,8 @@ private static void PauseAllAnimations() // 씬의 글로벌 볼륨 프로파일을 흑백으로 교체하고 weight를 0 → 1로 페이드 (완전 흑백) // 기존 프로파일(그레인/모션블러 포함)이 통째로 빠지므로 정지 화면에서 지글거림도 없다 - private async Awaitable FadeToGrayscale(float duration) + // 같은 씬 어디서든 참조로 호출 가능. 되돌리려면 FadeToColor 사용. + public async Awaitable FadeToGrayscale(float duration) { if (_grayscaleProfile == null || _globalVolume == null) { @@ -80,6 +86,14 @@ private async Awaitable FadeToGrayscale(float duration) return; } + // 원래 볼륨 상태를 기억해 둔다 (FadeToColor 복원용). 이미 흑백이면 덮어쓰지 않는다. + if (!_grayscaleActive) + { + _preGrayscaleProfile = _globalVolume.sharedProfile; + _preGrayscaleWeight = _globalVolume.weight; + _grayscaleActive = true; + } + // sharedProfile로 물려야 에셋이 복제·수정되지 않는다 (페이드는 weight로만) // 씬 오브젝트의 프로퍼티 변경이라 플레이 종료 시 원래대로 돌아온다 _globalVolume.sharedProfile = _grayscaleProfile; @@ -89,14 +103,45 @@ private async Awaitable FadeToGrayscale(float duration) foreach (var cam in FindObjectsByType()) cam.GetUniversalAdditionalCameraData().renderPostProcessing = true; + await FadeVolumeWeight(0f, 1f, duration); + } + + // 흑백 → 원래 컬러로 되돌린다. weight를 0으로 뺀 뒤, FadeToGrayscale가 기억해둔 원래 프로파일/weight로 복원. + // 흑백 상태가 아니면 아무것도 하지 않는다. 같은 씬 어디서든 참조로 호출 가능. + public async Awaitable FadeToColor(float duration) + { + if (_globalVolume == null || !_grayscaleActive) + return; + + await FadeVolumeWeight(_globalVolume.weight, 0f, duration); + + _globalVolume.sharedProfile = _preGrayscaleProfile; + _globalVolume.weight = _preGrayscaleWeight; + _grayscaleActive = false; + } + + // 인스펙터 UnityEvent에서 호출용 void 래퍼. + // (async 메서드는 반환형이 void가 아니라 UnityEvent 드롭다운에 안 뜬다 — 여기서 fire-and-forget으로 감싼다) + public void FadeToGrayscaleEvent(float duration) => _ = FadeToGrayscale(duration); + public void FadeToColorEvent(float duration) => _ = FadeToColor(duration); + + // 글로벌 볼륨 weight를 from → to로 duration 동안 페이드 (duration ≤ 0이면 즉시 to) + private async Awaitable FadeVolumeWeight(float from, float to, float duration) + { + if (duration <= 0f) + { + _globalVolume.weight = to; + return; + } + float timer = 0f; while (timer < duration) { timer += Time.deltaTime; - _globalVolume.weight = Mathf.Clamp01(timer / duration); + _globalVolume.weight = Mathf.Lerp(from, to, Mathf.Clamp01(timer / duration)); await Awaitable.NextFrameAsync(destroyCancellationToken); } - _globalVolume.weight = 1f; + _globalVolume.weight = to; } // 씬 로드 시 이 씬 전용 스카이박스를 적용 diff --git a/Assets/07_Data/DialogGraph/Chapter5/Chapter5_Yuna1.dlg b/Assets/07_Data/DialogGraph/Chapter5/Chapter5_Yuna1.dlg index 7fe8317f..ac9dc34d 100644 --- a/Assets/07_Data/DialogGraph/Chapter5/Chapter5_Yuna1.dlg +++ b/Assets/07_Data/DialogGraph/Chapter5/Chapter5_Yuna1.dlg @@ -663,7 +663,7 @@ MonoBehaviour: - rid: 4848514747977957636 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957637 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -855,7 +855,7 @@ MonoBehaviour: - rid: 4848514747977957659 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957660 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -1047,7 +1047,7 @@ MonoBehaviour: - rid: 4848514747977957682 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957683 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -1239,7 +1239,7 @@ MonoBehaviour: - rid: 4848514747977957705 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957706 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -1430,7 +1430,7 @@ MonoBehaviour: - rid: 4848514747977957728 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957729 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -1622,7 +1622,7 @@ MonoBehaviour: - rid: 4848514747977957751 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957752 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -1813,7 +1813,7 @@ MonoBehaviour: - rid: 4848514747977957774 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957775 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -2004,7 +2004,7 @@ MonoBehaviour: - rid: 4848514747977957797 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957798 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -2149,7 +2149,7 @@ MonoBehaviour: - rid: 4848514747977957809 type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: + m_Value: GrayVolume - rid: 4848514747977957810 type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -2195,7 +2195,7 @@ MonoBehaviour: - rid: 4848514747977957820 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: fbf0ad532c5e65e4189e65ef2439d507, type: 3} - rid: 4848514747977957821 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -2418,7 +2418,7 @@ MonoBehaviour: - rid: 4848514747977957844 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: df289b60c0e4b68458f17c07abe9accd, type: 3} - rid: 4848514747977957845 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -2609,7 +2609,7 @@ MonoBehaviour: - rid: 4848514747977957867 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: fbf0ad532c5e65e4189e65ef2439d507, type: 3} - rid: 4848514747977957868 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: @@ -2800,7 +2800,7 @@ MonoBehaviour: - rid: 4848514747977957890 type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: - m_Value: {fileID: 0} + m_Value: {fileID: 8300000, guid: fbf0ad532c5e65e4189e65ef2439d507, type: 3} - rid: 4848514747977957891 type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} data: diff --git a/Assets/11_Audio/BGM/Etc/Horror.mp3 b/Assets/11_Audio/BGM/Etc/Horror.mp3 new file mode 100644 index 00000000..2ab6b833 --- /dev/null +++ b/Assets/11_Audio/BGM/Etc/Horror.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d49a58cd36b7c5d045cc5ffbc576a1d5539f6d086267817065e83b4fe91a4762 +size 526001 diff --git a/Assets/11_Audio/BGM/Etc/Horror.mp3.meta b/Assets/11_Audio/BGM/Etc/Horror.mp3.meta new file mode 100644 index 00000000..84dd213c --- /dev/null +++ b/Assets/11_Audio/BGM/Etc/Horror.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: df289b60c0e4b68458f17c07abe9accd +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/11_Audio/BGM/Etc/Mute.mp3 b/Assets/11_Audio/BGM/Etc/Mute.mp3 new file mode 100644 index 00000000..a979c4b1 --- /dev/null +++ b/Assets/11_Audio/BGM/Etc/Mute.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:780444a89da5be2436e6fd7e0abc95d0099caa393cf3af815da88a97efeebcc5 +size 1440705 diff --git a/Assets/11_Audio/BGM/Etc/Mute.mp3.meta b/Assets/11_Audio/BGM/Etc/Mute.mp3.meta new file mode 100644 index 00000000..9494f73d --- /dev/null +++ b/Assets/11_Audio/BGM/Etc/Mute.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: fbf0ad532c5e65e4189e65ef2439d507 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: