using System.Collections; using UnityEngine; using UnityEngine.Events; public class JunpyoCollapseEvent : MonoBehaviour { [Header("구준표")] [SerializeField] private Animator junpyoAnimator; [SerializeField] private string collapseTrigger = "Collapse"; [Header("플레이어 시선")] [SerializeField] private Transform xrOrigin; [SerializeField] private Transform playerCamera; [SerializeField] private Transform lookTarget; [Tooltip("구준표 쪽으로 화면이 돌아가는 시간")] [SerializeField] private float lookDuration = 0.4f; [Tooltip("화면 전환을 시작하고 몇 초 뒤 쓰러질지")] [SerializeField] private float collapseStartDelay = 0.15f; [Header("페이드 타이밍")] [Tooltip("쓰러지기 시작한 뒤 페이드 아웃까지 기다리는 시간")] [SerializeField] private float fadeDelay = 1.3f; [Header("쓰러진 뒤 실행")] [SerializeField] private UnityEvent onCollapseFinished; private bool hasPlayed; public void PlayCollapse() { if (hasPlayed) return; if (junpyoAnimator == null) { Debug.LogWarning( "[JunpyoCollapseEvent] 구준표 Animator가 연결되지 않았습니다." ); return; } if (xrOrigin == null || playerCamera == null || lookTarget == null) { Debug.LogWarning( "[JunpyoCollapseEvent] 플레이어 시선 설정이 비어 있습니다." ); return; } hasPlayed = true; StartCoroutine(CollapseRoutine()); } private IEnumerator CollapseRoutine() { // 구준표 방향으로 화면 전환 시작 StartCoroutine(LookAtJunpyoRoutine()); // 화면이 돌아가기 시작한 뒤 잠깐 기다림 yield return new WaitForSeconds(collapseStartDelay); // 구준표 쓰러지는 애니메이션 실행 junpyoAnimator.ResetTrigger(collapseTrigger); junpyoAnimator.SetTrigger(collapseTrigger); // 쓰러지는 모습을 보여준 뒤 페이드 아웃 yield return new WaitForSeconds(fadeDelay); onCollapseFinished?.Invoke(); } private IEnumerator LookAtJunpyoRoutine() { Vector3 cameraForward = playerCamera.forward; cameraForward.y = 0f; Vector3 targetDirection = lookTarget.position - playerCamera.position; targetDirection.y = 0f; if (cameraForward.sqrMagnitude < 0.001f || targetDirection.sqrMagnitude < 0.001f) { yield break; } cameraForward.Normalize(); targetDirection.Normalize(); // 현재 시선에서 구준표까지 필요한 좌우 회전각 float totalAngle = Vector3.SignedAngle( cameraForward, targetDirection, Vector3.up ); float duration = Mathf.Max(0.01f, lookDuration); float elapsed = 0f; float previousAngle = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / duration); // 부드럽게 시작하고 부드럽게 멈춤 float easedT = t * t * (3f - 2f * t); float currentAngle = totalAngle * easedT; float frameAngle = currentAngle - previousAngle; // 카메라 현재 위치를 중심으로 XR Origin 회전 // 플레이어 위치가 옆으로 밀리는 현상을 방지 xrOrigin.RotateAround( playerCamera.position, Vector3.up, frameAngle ); previousAngle = currentAngle; yield return null; } } public void ResetCollapse() { StopAllCoroutines(); hasPlayed = false; if (junpyoAnimator != null) junpyoAnimator.ResetTrigger(collapseTrigger); } [ContextMenu("Test Collapse")] private void TestCollapse() { PlayCollapse(); } [ContextMenu("Reset Collapse")] private void TestResetCollapse() { ResetCollapse(); } }