using UnityEngine; using UnityEngine.SceneManagement; using System.Collections; using TMPro; public class SceneLoader : MonoBehaviour { // ========================= // 싱글톤(전역 접근용) // ========================= public static SceneLoader Instance; // ========================= // 로딩 UI 연결 // ========================= [Header("로딩 UI 연결")] public GameObject loadingCanvas; // 하이어라키의 'load canvas' 전체(로딩 화면 전체) public CanvasGroup backgroundGroup; // 배경(검정 페이드)용 CanvasGroup public TextMeshProUGUI tipText; // Tip 텍스트(TMP) // ========================= // 로딩 시 나타날 요소들 // ========================= [Header("로딩 시 나타날 요소들")] public GameObject loadingTextObject; // "Loading..." 텍스트 오브젝트 public GameObject tipBarObject; // TipBar(막대) 오브젝트(부모일 수도 있음) [Header("TipBar 실제 배경(선택)")] public RectTransform tipBarBackgroundRect; // ========================= // 설정 // ========================= [Header("설정")] public string[] tips; // 랜덤으로 뽑을 팁 문구 배열 public float fadeDuration = 1.0f; // 배경 페이드 속도(초) // ========================= // TipBar 자동 리사이즈 설정 // ========================= [Header("TipBar 자동 리사이즈(코드)")] [Tooltip("Tip 텍스트 줄바꿈 기준 = 화면 폭의 몇 %를 쓸지")] [Range(0.4f, 0.95f)] public float wrapWidthScreenRatio = 0.75f; [Tooltip("TipBar 안쪽 여백(좌/우 합, 상/하 합)")] public Vector2 tipPadding = new Vector2(120f, 60f); [Tooltip("TipBar 최소 높이")] public float tipBarMinHeight = 70f; // ========================= // 내부 캐시 // ========================= private RectTransform _tipBarRect; private RectTransform _tipTextRect; // private float _tipBarBaseHeight; // 사용하지 않는 변수이므로 삭제하여 경고 해결 [Header("TipBar 기본 높이(1줄 기준)")] public float tipBarBaseHeight = 220f; private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); return; } if (loadingCanvas != null) loadingCanvas.SetActive(false); if (tipText != null) _tipTextRect = tipText.GetComponent(); if (tipBarBackgroundRect != null) _tipBarRect = tipBarBackgroundRect; else if (tipBarObject != null) _tipBarRect = tipBarObject.GetComponent(); if (tipText != null) { tipText.enableWordWrapping = true; tipText.overflowMode = TextOverflowModes.Overflow; } } public void LoadSceneWithFade(string sceneName) { StartCoroutine(LoadProcess(sceneName)); } private IEnumerator LoadProcess(string sceneName) { if (loadingTextObject != null) loadingTextObject.SetActive(false); if (tipBarObject != null) tipBarObject.SetActive(false); if (loadingCanvas != null) loadingCanvas.SetActive(true); if (backgroundGroup != null) backgroundGroup.alpha = 0f; // ★ 수정됨: Fade 호출 시 backgroundGroup을 함께 전달 yield return StartCoroutine(Fade(1f, backgroundGroup)); if (loadingTextObject != null) loadingTextObject.SetActive(true); if (tipBarObject != null) tipBarObject.SetActive(true); if (tipText != null) { if (tips != null && tips.Length > 0) { int randomIndex = Random.Range(0, tips.Length); tipText.text = $"Tip! : {tips[randomIndex]}"; } else { tipText.text = ""; } ResizeTipBarToFitText(); yield return null; ResizeTipBarToFitText(); } AsyncOperation op = SceneManager.LoadSceneAsync(sceneName); op.allowSceneActivation = false; float timer = 0f; while (timer < 2.0f) { timer += Time.deltaTime; yield return null; } op.allowSceneActivation = true; if (loadingTextObject != null) loadingTextObject.SetActive(false); if (tipBarObject != null) tipBarObject.SetActive(false); // ★ 수정됨: Fade 호출 시 backgroundGroup을 함께 전달 yield return StartCoroutine(Fade(0f, backgroundGroup)); if (loadingCanvas != null) loadingCanvas.SetActive(false); } // ========================= // 배경 페이드 함수 (안전 코드 적용) // ========================= private IEnumerator Fade(float targetAlpha, CanvasGroup canvasGroup) { if (canvasGroup == null) { Debug.LogWarning("SceneLoader: 페이드할 CanvasGroup이 없습니다!"); yield break; } // fadeDuration이 0인 경우 방지 float duration = Mathf.Max(0.01f, fadeDuration); float speed = 1f / duration; // null 체크 및 오차 범위 체크 추가 while (canvasGroup != null && !Mathf.Approximately(canvasGroup.alpha, targetAlpha)) { canvasGroup.alpha = Mathf.MoveTowards(canvasGroup.alpha, targetAlpha, speed * Time.unscaledDeltaTime); yield return null; } if (canvasGroup != null) { canvasGroup.alpha = targetAlpha; } } private void ResizeTipBarToFitText() { if (tipText == null || _tipBarRect == null || _tipTextRect == null) return; float scale = 1f; var canvas = tipText.canvas; if (canvas != null) scale = canvas.scaleFactor; float safeWrapWidth = (Screen.width * wrapWidthScreenRatio) / Mathf.Max(0.0001f, scale); safeWrapWidth = Mathf.Clamp(safeWrapWidth, 600f, 1400f); float wrapWidth = Mathf.Max(200f, safeWrapWidth - tipPadding.x); _tipTextRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, wrapWidth); tipText.enableWordWrapping = true; tipText.overflowMode = TextOverflowModes.Overflow; tipText.ForceMeshUpdate(); Vector2 preferred = tipText.GetPreferredValues(tipText.text, wrapWidth, 0f); float textHeight = Mathf.Ceil(preferred.y); _tipTextRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, textHeight); float neededHeight = textHeight + tipPadding.y; float barHeight = Mathf.Max(tipBarBaseHeight, neededHeight, tipBarMinHeight); _tipBarRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, barHeight); } }