From 2c026cae7be73e9202c81198137da097ed8c7a70 Mon Sep 17 00:00:00 2001 From: Jeonghyeon Ha Date: Tue, 15 Jul 2025 13:40:43 +0900 Subject: [PATCH] =?UTF-8?q?DDD-43=20=ED=95=B4=EC=83=81=20=EB=B0=B0=20?= =?UTF-8?q?=EC=A1=B0=EC=9E=91=20-=20=ED=9A=8C=EC=A0=84=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=ED=8B=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_Scripts/Ship/VoyagePlayerShipMovement.cs | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs b/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs index 00b175307..7e21635af 100644 --- a/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs +++ b/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs @@ -37,23 +37,28 @@ public class VoyagePlayerShipMovement : MonoBehaviour [Header("Tilt Settings")] [SerializeField] private float maxTiltAngle = 15f; [SerializeField] private float tiltSpeed = 5f; - [SerializeField] private string meshObjectName = "Ship_Mesh"; // 메시 오브젝트의 이름 - private Transform meshTransform; // 메시 트랜스폼 - private float currentTilt = 0f; - private Quaternion originalMeshRotation; // 메시의 초기 회전값 저장 - + [SerializeField] private float returnSpeed = 3f; // 원래 자세로 돌아오는 속도 + [SerializeField] private float angularVelocityMultiplier = 2f; // 각속도 영향력 + [SerializeField] private string meshObjectName = "Ship_Mesh"; + + private Transform _meshTransform; + private float _currentTilt = 0f; + private Quaternion _originalMeshRotation; + private float _lastRotationY; // 이전 프레임의 Y축 회전값 + private float _currentAngularVelocity; // 현재 각속도 + private void Start() { - // 하위 오브젝트에서 메시 찾기 - meshTransform = transform.Find(meshObjectName); - if (meshTransform == null) + _meshTransform = transform.Find(meshObjectName); + if (_meshTransform == null) { Debug.LogError($"메시 오브젝트를 찾을 수 없습니다: {meshObjectName}"); + enabled = false; return; } - // 메시의 초기 회전값 저장 - originalMeshRotation = meshTransform.localRotation; + _originalMeshRotation = _meshTransform.localRotation; + _lastRotationY = transform.eulerAngles.y; } private void FixedUpdate() @@ -68,6 +73,7 @@ public class VoyagePlayerShipMovement : MonoBehaviour // 입력이 없을 때는 서서히 감속 currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime); } + UpdateMeshRotationTilt(); ApplyDrag(); ApplyMovement(); @@ -121,38 +127,46 @@ public class VoyagePlayerShipMovement : MonoBehaviour float currentRotationSpeed = rotationSpeed * (currentSpeed / maxSpeed); currentRotationSpeed = Mathf.Max(currentRotationSpeed, rotationSpeed * 0.3f); - // 회전 방향에 따른 목표 기울기 계산 - float turnDirection = Vector3.SignedAngle(transform.forward, inputDirection, Vector3.up); - float targetTilt = -Mathf.Sign(turnDirection) * maxTiltAngle * (currentSpeed / maxSpeed); - - // 현재 기울기를 목표 기울기로 부드럽게 보간 - currentTilt = Mathf.Lerp(currentTilt, targetTilt, tiltSpeed * Time.fixedDeltaTime); - // 기본 회전 적용 (오브젝트 전체) transform.rotation = Quaternion.RotateTowards( transform.rotation, targetRotation, currentRotationSpeed * Time.fixedDeltaTime ); - - // 메시에만 z축 기울기 적용 - if (meshTransform != null) - { - meshTransform.localRotation = originalMeshRotation * Quaternion.Euler(0, 0, currentTilt); - } - } - else - { - // 입력이 없을 때는 기울기를 서서히 0으로 - currentTilt = Mathf.Lerp(currentTilt, 0f, tiltSpeed * Time.fixedDeltaTime); - - if (meshTransform != null) - { - meshTransform.localRotation = originalMeshRotation * Quaternion.Euler(0, 0, currentTilt); - } } } + private void UpdateMeshRotationTilt() + { + if (_meshTransform is null) return; + + // 현재 Y축 회전값과 각속도 계산 + float currentRotationY = transform.eulerAngles.y; + float deltaRotation = Mathf.DeltaAngle(_lastRotationY, currentRotationY); + _currentAngularVelocity = deltaRotation / Time.fixedDeltaTime; + + // 목표 틸트 각도 계산 + float targetTilt = -_currentAngularVelocity * angularVelocityMultiplier; + targetTilt = Mathf.Clamp(targetTilt, -maxTiltAngle, maxTiltAngle); + + // 틸트 적용 또는 복귀 + if (Mathf.Abs(_currentAngularVelocity) > 0.1f) + { + _currentTilt = Mathf.Lerp(_currentTilt, targetTilt, tiltSpeed * Time.fixedDeltaTime); + } + else + { + // 입력이 없을 때는 원래 자세로 천천히 복귀 + _currentTilt = Mathf.Lerp(_currentTilt, 0f, returnSpeed * Time.fixedDeltaTime); + } + + // 메시에 틸트 적용 + _meshTransform.localRotation = _originalMeshRotation * Quaternion.Euler(0, 0, _currentTilt); + + _lastRotationY = currentRotationY; + } + + private void ApplyDrag() { currentSpeed *= dragFactor; @@ -196,9 +210,9 @@ public class VoyagePlayerShipMovement : MonoBehaviour DrawDebugLine(forwardDirectionLine, transform.forward, debugLineLength, 0); // 메시의 위쪽 방향 표시 (틸팅 반영) - if (meshTransform is not null) + if (_meshTransform is not null) { - DrawDebugLine(upDirectionLine, meshTransform.up, debugLineLength, debugLineHeightStep); + DrawDebugLine(upDirectionLine, _meshTransform.up, debugLineLength, debugLineHeightStep); } // 입력 방향 표시 (두 단계 위) @@ -245,7 +259,7 @@ public class VoyagePlayerShipMovement : MonoBehaviour // 에디터에서 메시 오브젝트 이름이 변경될 때 자동으로 찾기 if (Application.isEditor && !Application.isPlaying) { - meshTransform = transform.Find(meshObjectName); + _meshTransform = transform.Find(meshObjectName); } } } \ No newline at end of file