using System.Diagnostics; using TMPro; using UnityEngine; using UnityEngine.UI; namespace ADOFAIRenderer.Component { public class EscapeHandlerUI : MonoBehaviour { private GameObject _containerObj = null!; private TextMeshProUGUI _textComponent = null!; private Stopwatch? _escapeStopwatch; private void Start() { // UI 레이어(5) 설정 gameObject.layer = 5; // Canvas 설정 var canvas = gameObject.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = 10000; // 디버그 모니터보다 위에 오도록 설정 // 해상도 대응 캔버스 스케일러 설정 var scaler = gameObject.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920, 1080); scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; scaler.matchWidthOrHeight = 0.5f; gameObject.AddComponent(); // 1. 컨테이너 및 배경 패널 오브젝트 생성 _containerObj = new GameObject("EscapeContainer"); _containerObj.transform.SetParent(transform, false); _containerObj.layer = 5; var bgImage = _containerObj.AddComponent(); // 고급스러운 다크톤 아크릴 감성 bgImage.color = new Color(0.05f, 0.05f, 0.07f, 0.85f); var containerRect = _containerObj.GetComponent(); containerRect.anchorMin = new Vector2(0.5f, 0.5f); containerRect.anchorMax = new Vector2(0.5f, 0.5f); containerRect.pivot = new Vector2(0.5f, 0.5f); containerRect.anchoredPosition = Vector2.zero; // 화면 중앙 containerRect.sizeDelta = new Vector2(460, 160); // 2. 텍스트 오브젝트 생성 var textObj = new GameObject("EscapeText"); textObj.transform.SetParent(_containerObj.transform, false); textObj.layer = 5; _textComponent = textObj.AddComponent(); _textComponent.alignment = TextAlignmentOptions.Center; _textComponent.fontSize = 60; _textComponent.textWrappingMode = TextWrappingModes.NoWrap; _textComponent.richText = true; // 게임의 기본 폰트 적용 (RDString.fontData.fontTMP) if (RDString.fontData.fontTMP != null) _textComponent.font = RDString.fontData.fontTMP; var textRect = textObj.GetComponent(); textRect.anchorMin = Vector2.zero; textRect.anchorMax = Vector2.one; textRect.offsetMin = new Vector2(10, 10); textRect.offsetMax = new Vector2(-10, -10); // 초기 상태는 비활성화 _containerObj.SetActive(false); } private void Update() { // 렌더링이 더 이상 활성화되어 있지 않으면 자가 파괴 if (!RenderMod.IsRendering) { Destroy(gameObject); return; } if (Input.GetKey(KeyCode.Escape)) { if (_escapeStopwatch == null) { _escapeStopwatch = new Stopwatch(); _escapeStopwatch.Start(); _containerObj.SetActive(true); } var elapsed = (float)_escapeStopwatch.Elapsed.TotalSeconds; var remaining = Mathf.Max(0f, 3f - elapsed); // 남은 시간 텍스트 업데이트 _textComponent.text = $"탈출까지 {remaining:F1}초..\nEsc 키를 계속 누르고 계세요"; // 마이크로 펄스 애니메이션 적용 (누르는 동안 컨테이너 전체 크기가 부드럽게 커짐) var scale = 1.0f + (elapsed / 3.0f) * 0.15f; _containerObj.transform.localScale = new Vector3(scale, scale, 1f); if (elapsed < 3f) return; _escapeStopwatch.Stop(); _escapeStopwatch = null; _containerObj.transform.localScale = Vector3.one; // 스케일 초기화 _containerObj.SetActive(false); // 렌더링 취소 및 씬 이탈 if (RenderManager.Instance) RenderManager.Instance.CancelRender(); } else { if (_escapeStopwatch == null) return; _escapeStopwatch.Stop(); _escapeStopwatch = null; _containerObj.transform.localScale = Vector3.one; // 스케일 초기화 _containerObj.SetActive(false); } } private void OnDestroy() { if (_escapeStopwatch == null) return; _escapeStopwatch.Stop(); _escapeStopwatch = null; } } }