2026-07-14 씬체인지
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GameManager : MonoBehaviour
|
||||
public class GameManager : MonoBehaviour,ISceneInitializable
|
||||
{
|
||||
public static GameManager Instance { get; private set; }
|
||||
|
||||
public GameObject Player {get; private set;}
|
||||
public PlayerController PController => Player != null ? Player.GetComponent<PlayerController>() : null;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
@@ -15,4 +18,9 @@ private void Awake()
|
||||
Destroy(gameObject); //이미 인스턴스가 있으면 자신을 파괴
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSceneLoaded()
|
||||
{
|
||||
Player = GameObject.FindWithTag("Player");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,23 +13,28 @@ public class LocalManager : MonoBehaviour
|
||||
// BGM 재생 시작 후 씬 전환까지 대기 시간(초)
|
||||
[SerializeField, Min(0f)] private float _caffebeneSceneChangeDelay = 13f;
|
||||
|
||||
private VolumeProfile _grayscaleProfile;
|
||||
// 채도 -100으로 만들어둔 공용 프로파일 (Assets/Settings/GrayscaleVolumeProfile)
|
||||
[SerializeField] private VolumeProfile _grayscaleProfile;
|
||||
// 씬에 이미 있는 글로벌 볼륨 — 새로 만들지 않고 이 볼륨의 프로파일을 흑백으로 교체한다
|
||||
[SerializeField] private Volume _globalVolume;
|
||||
|
||||
public void NextScene(int delay)
|
||||
{
|
||||
_ = Util.RunDelayed((float)delay,()=>SceneLoadManager.Instance.RequestSceneChange(_nextSceneName));
|
||||
}
|
||||
|
||||
public void CaffebeneNextSceneChange()
|
||||
public void CaffebeneNextSceneChange(int delay)
|
||||
{
|
||||
_ = CaffebeneSequence();
|
||||
_ = CaffebeneSequence(delay);
|
||||
}
|
||||
|
||||
// 모든 애니메이션 정지 → 시야 흑백 페이드 → BGM 재생 → 대기 후 씬 전환
|
||||
private async Awaitable CaffebeneSequence()
|
||||
private async Awaitable CaffebeneSequence(int delay)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Awaitable.WaitForSecondsAsync((float)delay);
|
||||
|
||||
PauseAllAnimations();
|
||||
|
||||
await FadeToGrayscale(_grayscaleFadeTime);
|
||||
@@ -59,38 +64,32 @@ private static void PauseAllAnimations()
|
||||
particle.Pause();
|
||||
}
|
||||
|
||||
// 런타임 전용 글로벌 볼륨을 만들어 채도를 0 → -100으로 페이드 (완전 흑백)
|
||||
// 씬의 글로벌 볼륨 프로파일을 흑백으로 교체하고 weight를 0 → 1로 페이드 (완전 흑백)
|
||||
// 기존 프로파일(그레인/모션블러 포함)이 통째로 빠지므로 정지 화면에서 지글거림도 없다
|
||||
private async Awaitable FadeToGrayscale(float duration)
|
||||
{
|
||||
var volumeObj = new GameObject("Grayscale Volume (Runtime)");
|
||||
var volume = volumeObj.AddComponent<Volume>();
|
||||
volume.isGlobal = true;
|
||||
volume.priority = 100f;
|
||||
if (_grayscaleProfile == null || _globalVolume == null)
|
||||
{
|
||||
Debug.LogWarning("[LocalManager] _grayscaleProfile 또는 _globalVolume이 비어 있어 흑백 페이드를 건너뜁니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
_grayscaleProfile = ScriptableObject.CreateInstance<VolumeProfile>();
|
||||
var colorAdjustments = _grayscaleProfile.Add<ColorAdjustments>();
|
||||
colorAdjustments.saturation.Override(0f);
|
||||
volume.profile = _grayscaleProfile;
|
||||
// sharedProfile로 물려야 에셋이 복제·수정되지 않는다 (페이드는 weight로만)
|
||||
// 씬 오브젝트의 프로퍼티 변경이라 플레이 종료 시 원래대로 돌아온다
|
||||
_globalVolume.sharedProfile = _grayscaleProfile;
|
||||
_globalVolume.weight = 0f;
|
||||
|
||||
// 카메라에 포스트 프로세싱이 꺼져 있으면 켠다
|
||||
var mainCam = Camera.main;
|
||||
if (mainCam != null)
|
||||
mainCam.GetUniversalAdditionalCameraData().renderPostProcessing = true;
|
||||
// 메인 카메라뿐 아니라 RecordCamera 등 모든 카메라에 포스트 프로세싱을 켠다
|
||||
foreach (var cam in FindObjectsByType<Camera>())
|
||||
cam.GetUniversalAdditionalCameraData().renderPostProcessing = true;
|
||||
|
||||
float timer = 0f;
|
||||
while (timer < duration)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
colorAdjustments.saturation.value = Mathf.Lerp(0f, -100f, Mathf.Clamp01(timer / duration));
|
||||
_globalVolume.weight = Mathf.Clamp01(timer / duration);
|
||||
await Awaitable.NextFrameAsync(destroyCancellationToken);
|
||||
}
|
||||
colorAdjustments.saturation.value = -100f;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 런타임 생성한 프로필은 씬 언로드로 자동 파괴되지 않으므로 직접 정리
|
||||
if (_grayscaleProfile != null)
|
||||
Destroy(_grayscaleProfile);
|
||||
_globalVolume.weight = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +196,11 @@ private async Awaitable SceneChange(string sceneName)
|
||||
//스카이 박스 페이드 아웃
|
||||
await FadeSkybox(_skyboxNormalExposure, 0f, _skyboxFadeTime);
|
||||
|
||||
// 시야(암전 구체)도 완전히 어두워질 때까지 페이드 — 아래 교체/이동 순간을 씬 오브젝트째로 가린다
|
||||
var pc = GameManager.Instance != null ? GameManager.Instance.PController : null;
|
||||
if (pc != null)
|
||||
await pc.FadeSight(false, 1f);
|
||||
|
||||
// 검게 된 상태에서 머티리얼 교체 (교체 순간이 가려져 깜빡임 없음)
|
||||
RenderSettings.skybox = _runtimeLoadingSkybox;
|
||||
|
||||
@@ -203,6 +208,10 @@ private async Awaitable SceneChange(string sceneName)
|
||||
// (로딩 룸은 카메라를 따라다니므로 함께 이동한다)
|
||||
MovePlayerToLoadingArea();
|
||||
|
||||
// 로딩 룸에 도착했으니 시야를 다시 연다 (스카이박스 페이드 인과 동시 진행)
|
||||
if (pc != null)
|
||||
_ = pc.FadeSight(true, 1f);
|
||||
|
||||
//스카이 박스 페이드 인
|
||||
await FadeSkybox(0f, _skyboxNormalExposure, _skyboxFadeTime);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user