DDD-43 해상 배 조작 - 회전에 따른 틸팅

This commit is contained in:
Jeonghyeon Ha 2025-07-15 13:40:43 +09:00
parent 70702f3235
commit 2c026cae7b

View File

@ -37,23 +37,28 @@ public class VoyagePlayerShipMovement : MonoBehaviour
[Header("Tilt Settings")] [Header("Tilt Settings")]
[SerializeField] private float maxTiltAngle = 15f; [SerializeField] private float maxTiltAngle = 15f;
[SerializeField] private float tiltSpeed = 5f; [SerializeField] private float tiltSpeed = 5f;
[SerializeField] private string meshObjectName = "Ship_Mesh"; // 메시 오브젝트의 이름 [SerializeField] private float returnSpeed = 3f; // 원래 자세로 돌아오는 속도
private Transform meshTransform; // 메시 트랜스폼 [SerializeField] private float angularVelocityMultiplier = 2f; // 각속도 영향력
private float currentTilt = 0f; [SerializeField] private string meshObjectName = "Ship_Mesh";
private Quaternion originalMeshRotation; // 메시의 초기 회전값 저장
private Transform _meshTransform;
private float _currentTilt = 0f;
private Quaternion _originalMeshRotation;
private float _lastRotationY; // 이전 프레임의 Y축 회전값
private float _currentAngularVelocity; // 현재 각속도
private void Start() private void Start()
{ {
// 하위 오브젝트에서 메시 찾기 _meshTransform = transform.Find(meshObjectName);
meshTransform = transform.Find(meshObjectName); if (_meshTransform == null)
if (meshTransform == null)
{ {
Debug.LogError($"메시 오브젝트를 찾을 수 없습니다: {meshObjectName}"); Debug.LogError($"메시 오브젝트를 찾을 수 없습니다: {meshObjectName}");
enabled = false;
return; return;
} }
// 메시의 초기 회전값 저장 _originalMeshRotation = _meshTransform.localRotation;
originalMeshRotation = meshTransform.localRotation; _lastRotationY = transform.eulerAngles.y;
} }
private void FixedUpdate() private void FixedUpdate()
@ -68,6 +73,7 @@ public class VoyagePlayerShipMovement : MonoBehaviour
// 입력이 없을 때는 서서히 감속 // 입력이 없을 때는 서서히 감속
currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime); currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime);
} }
UpdateMeshRotationTilt();
ApplyDrag(); ApplyDrag();
ApplyMovement(); ApplyMovement();
@ -121,38 +127,46 @@ public class VoyagePlayerShipMovement : MonoBehaviour
float currentRotationSpeed = rotationSpeed * (currentSpeed / maxSpeed); float currentRotationSpeed = rotationSpeed * (currentSpeed / maxSpeed);
currentRotationSpeed = Mathf.Max(currentRotationSpeed, rotationSpeed * 0.3f); 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 = Quaternion.RotateTowards(
transform.rotation, transform.rotation,
targetRotation, targetRotation,
currentRotationSpeed * Time.fixedDeltaTime 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() private void ApplyDrag()
{ {
currentSpeed *= dragFactor; currentSpeed *= dragFactor;
@ -196,9 +210,9 @@ public class VoyagePlayerShipMovement : MonoBehaviour
DrawDebugLine(forwardDirectionLine, transform.forward, debugLineLength, 0); 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) if (Application.isEditor && !Application.isPlaying)
{ {
meshTransform = transform.Find(meshObjectName); _meshTransform = transform.Find(meshObjectName);
} }
} }
} }