diff --git a/Assets/0_Voyage/Ship/Player/PlayerShip.prefab b/Assets/0_Voyage/Ship/Player/PlayerShip.prefab index 80f5db653..51681ccde 100644 --- a/Assets/0_Voyage/Ship/Player/PlayerShip.prefab +++ b/Assets/0_Voyage/Ship/Player/PlayerShip.prefab @@ -105,18 +105,27 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 2607481b15fd548b18ca4897db56ab3f, type: 3} m_Name: m_EditorClassIdentifier: - maxSpeed: 10 - rotationSpeed: 120 - accelerationRate: 2 + maxSpeed: 20 + rotationSpeed: 180 + accelerationRate: 1 minSpeedThreshold: 0.1 dragFactor: 0.98 turnSpeedPenalty: 0.5 maxTurnAngle: 180 showDebugLines: 1 - debugLineLength: 4 - debugLineHeightStep: 0.1 - maxTiltAngle: 15 - tiltSpeed: 5 + debugLineLength: 5 + debugLineHeightStep: 0.02 + maxRotationTiltAngle: 15 + rotationTiltSpeed: 5 + RotationTiltReturnSpeed: 3 + angularVelocityMultiplier: 2 + maxAccelTiltAngle: 15 + accelTiltForce: 15 + accelTiltDamping: 0.9 + accelTiltSpeed: 10 + springStiffness: 30 + springDamping: 15 + meshObjectName: Ship_Mesh --- !u!1 &6407855916708530114 GameObject: m_ObjectHideFlags: 0 @@ -158,7 +167,7 @@ MeshFilter: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6407855916708530114} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} --- !u!23 &9176830315433650152 MeshRenderer: m_ObjectHideFlags: 0 diff --git a/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs b/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs index 7e21635af..43950d9a9 100644 --- a/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs +++ b/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs @@ -1,13 +1,13 @@ using UnityEngine; using UnityEngine.InputSystem; +using UnityEngine.Serialization; public class VoyagePlayerShipMovement : MonoBehaviour { [Header("Movement Settings")] - [SerializeField] private float maxSpeed = 10f; - - [SerializeField] private float rotationSpeed = 120f; - [SerializeField] private float accelerationRate = 2f; + [SerializeField] private float maxSpeed = 20f; + [SerializeField] private float rotationSpeed = 180f; + [SerializeField] private float accelerationRate = 1f; [SerializeField] private float minSpeedThreshold = 0.1f; [SerializeField] private float dragFactor = 0.98f; @@ -34,18 +34,34 @@ public class VoyagePlayerShipMovement : MonoBehaviour private float targetSpeed; private float currentSpeed; - [Header("Tilt Settings")] - [SerializeField] private float maxTiltAngle = 15f; - [SerializeField] private float tiltSpeed = 5f; - [SerializeField] private float returnSpeed = 3f; // 원래 자세로 돌아오는 속도 + [Header("Rotation Tilt Settings")] + [SerializeField] private float maxRotationTiltAngle = 15f; + [SerializeField] private float rotationTiltSpeed = 5f; + [SerializeField] private float RotationTiltReturnSpeed = 3f; // 원래 자세로 돌아오는 속도 [SerializeField] private float angularVelocityMultiplier = 2f; // 각속도 영향력 + + [Header("Acceleration Tilt Settings")] + [SerializeField] private float maxAccelTiltAngle = 15f; // 최대 가속 틸트 각도 + [SerializeField] private float accelTiltForce = 15f; // 틸트 강도 + [SerializeField] private float accelTiltDamping = 0.9f; // 틸트 감쇠 계수 + [SerializeField] private float accelTiltSpeed = 10f; // 스프링 보간속도 + [SerializeField] private float springStiffness = 30f; // 스프링 강성 + [SerializeField] private float springDamping = 15f; // 스프링 감쇠 + + [Header("Mesh Settings")] [SerializeField] private string meshObjectName = "Ship_Mesh"; private Transform _meshTransform; - private float _currentTilt = 0f; + // Rotation Tilt + private float _currentRotationTilt = 0f; + private float _lastRotationY; // 이전 프레임의 Y축 회전값 + private float _currentAngularVelocity; // 현재 각속도 + // Acceleration Tilt + private float _currentAccelTilt; + private float _accelTiltVelocity; + private float _prevSpeed; + private Quaternion _originalMeshRotation; - private float _lastRotationY; // 이전 프레임의 Y축 회전값 - private float _currentAngularVelocity; // 현재 각속도 private void Start() { @@ -73,11 +89,14 @@ public class VoyagePlayerShipMovement : MonoBehaviour // 입력이 없을 때는 서서히 감속 currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime); } - UpdateMeshRotationTilt(); - ApplyDrag(); ApplyMovement(); + // Cosmetic Mesh Tilting + UpdateMeshRotationTilt(); + UpdateAccelerationTilt(); + ApplyMeshTilt(); + #if UNITY_EDITOR if (showDebugLines) { @@ -86,7 +105,6 @@ public class VoyagePlayerShipMovement : MonoBehaviour #endif } - private void HandleMovement() { // 기본 목표 속도 계산 (입력 크기에 비례) @@ -147,25 +165,64 @@ public class VoyagePlayerShipMovement : MonoBehaviour // 목표 틸트 각도 계산 float targetTilt = -_currentAngularVelocity * angularVelocityMultiplier; - targetTilt = Mathf.Clamp(targetTilt, -maxTiltAngle, maxTiltAngle); + targetTilt = Mathf.Clamp(targetTilt, -maxRotationTiltAngle, maxRotationTiltAngle); // 틸트 적용 또는 복귀 if (Mathf.Abs(_currentAngularVelocity) > 0.1f) { - _currentTilt = Mathf.Lerp(_currentTilt, targetTilt, tiltSpeed * Time.fixedDeltaTime); + _currentRotationTilt = Mathf.Lerp(_currentRotationTilt, targetTilt, rotationTiltSpeed * Time.fixedDeltaTime); } else { // 입력이 없을 때는 원래 자세로 천천히 복귀 - _currentTilt = Mathf.Lerp(_currentTilt, 0f, returnSpeed * Time.fixedDeltaTime); + _currentRotationTilt = Mathf.Lerp(_currentRotationTilt, 0f, RotationTiltReturnSpeed * Time.fixedDeltaTime); } - - // 메시에 틸트 적용 - _meshTransform.localRotation = _originalMeshRotation * Quaternion.Euler(0, 0, _currentTilt); - + _lastRotationY = currentRotationY; } + private void UpdateAccelerationTilt() + { + // 가속도 계산 + float acceleration = (currentSpeed - _prevSpeed) / Time.fixedDeltaTime; + + // 스프링 물리 시스템 구현 + float springForce = -springStiffness * _currentAccelTilt; // 복원력 + float dampingForce = -springDamping * _accelTiltVelocity; // 감쇠력 + float accelerationForce = -acceleration * accelTiltForce; // 가속에 의한 힘 + + // 전체 힘 계산 + float totalForce = springForce + dampingForce + accelerationForce; + + // 가속도 계산 (F = ma, 질량은 1로 가정) + float tiltAcceleration = totalForce; + + // 속도 업데이트 + _accelTiltVelocity += tiltAcceleration; + _accelTiltVelocity *= accelTiltDamping; // 감쇠 적용 + _accelTiltVelocity *= Time.fixedDeltaTime; + + // 위치(각도) 업데이트 + _currentAccelTilt = Mathf.Lerp(_currentAccelTilt, _currentAccelTilt + _accelTiltVelocity, accelTiltSpeed * Time.fixedDeltaTime); + _currentAccelTilt = Mathf.Clamp(_currentAccelTilt, -maxAccelTiltAngle, maxAccelTiltAngle); + + _prevSpeed = currentSpeed; + + } + + private void ApplyMeshTilt() + { + if (_meshTransform is null) return; + + // 회전 틸트와 가속 틸트를 조합 + // 메시에 최종 틸트 적용 + _meshTransform.localRotation = _originalMeshRotation * Quaternion.Euler( + _currentAccelTilt, // X축 (가속 틸트) + 0, // Y축 + _currentRotationTilt // Z축 (회전 틸트) + ); + } + private void ApplyDrag() { @@ -190,8 +247,6 @@ public class VoyagePlayerShipMovement : MonoBehaviour public void OnMove(InputAction.CallbackContext context) { currentInput = context.ReadValue(); - // Debug Log this - Debug.Log(currentInput); } #if UNITY_EDITOR