using System.Collections; using UnityEngine; public class PlayerPushToPoint : MonoBehaviour { [Header("Player")] [SerializeField] private Transform xrOrigin; [SerializeField] private Transform playerCamera; [SerializeField] private CharacterController characterController; [Header("Push Direction")] [SerializeField] private Transform pushDirectionPoint; [Header("Push Settings")] [SerializeField] private float pushDistance = 0.9f; [SerializeField] private float pushDuration = 0.18f; private bool hasPushed; private bool isPushing; public void PushPlayerOnce() { if (hasPushed || isPushing) return; if (xrOrigin == null || playerCamera == null || pushDirectionPoint == null) { Debug.LogWarning( "[PlayerPushToPoint] 연결되지 않은 오브젝트가 있습니다." ); return; } hasPushed = true; StartCoroutine(PushRoutine()); } private IEnumerator PushRoutine() { isPushing = true; // 플레이어에서 포인트로 향하는 방향 Vector3 direction = pushDirectionPoint.position - playerCamera.position; // 수평 방향만 사용 direction.y = 0f; if (direction.sqrMagnitude < 0.001f) { Debug.LogWarning( "[PlayerPushToPoint] 밀기 방향을 계산할 수 없습니다." ); hasPushed = false; isPushing = false; yield break; } direction.Normalize(); Vector3 startPosition = xrOrigin.position; Vector3 targetPosition = startPosition + direction * pushDistance; // 시작 높이를 그대로 고정 float fixedY = startPosition.y; targetPosition.y = fixedY; bool controllerWasEnabled = characterController != null && characterController.enabled; // 밀리는 동안 바닥이나 장애물 때문에 위로 올라가지 않도록 끔 if (controllerWasEnabled) characterController.enabled = false; float duration = Mathf.Max(0.01f, pushDuration); float elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / duration); float easedT = 1f - Mathf.Pow(1f - t, 3f); Vector3 nextPosition = Vector3.Lerp(startPosition, targetPosition, easedT); // 매 프레임 Y값 강제 고정 nextPosition.y = fixedY; xrOrigin.position = nextPosition; yield return null; } // 마지막 위치 정확히 고정 xrOrigin.position = targetPosition; if (controllerWasEnabled) characterController.enabled = true; isPushing = false; } public void ResetPush() { StopAllCoroutines(); hasPushed = false; isPushing = false; if (characterController != null && !characterController.enabled) { characterController.enabled = true; } } [ContextMenu("Test Push")] private void TestPush() { PushPlayerOnce(); } [ContextMenu("Reset Push")] private void TestResetPush() { ResetPush(); } }