CapersProject/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs

179 lines
5.1 KiB
C#
Raw Normal View History

using UnityEngine;
using UnityEngine.InputSystem;
2025-07-15 10:24:43 +00:00
/// <summary>
/// 플레이어 배의 움직임을 제어하는 컴포넌트
/// 속도, 회전, 틸트, 파도 효과 등을 관리합니다.
/// </summary>
public class VoyagePlayerShipMovement : MonoBehaviour
{
2025-07-15 10:24:43 +00:00
#region Inspector Fields
[Header("기본 이동 설정")]
[Tooltip("배의 최대 이동 속도")]
2025-07-15 07:20:02 +00:00
[SerializeField] private float maxSpeed = 20f;
[SerializeField] private float accelerationRate = 1f;
2025-07-15 04:02:53 +00:00
[SerializeField] private float dragFactor = 0.98f;
2025-07-15 10:24:43 +00:00
[SerializeField] private float minSpeedThreshold = 0.1f;
[Header("회전 설정")]
[SerializeField] private float rotationSpeed = 270f;
[SerializeField] private float minRotationSpeed = 90f;
[SerializeField] private float rotationAccelerationRate = 5f;
[SerializeField] private float turnSpeedPenalty = 0.5f;
[SerializeField] private float maxTurnAngle = 180f;
2025-07-15 10:56:39 +00:00
2025-07-15 10:24:43 +00:00
#endregion
#region Private Fields
private Vector3 currentVelocity;
private Vector2 currentInput;
2025-07-15 10:56:39 +00:00
public Vector2 CurrentInput => currentInput;
2025-07-15 10:24:43 +00:00
private float currentRotationSpeed;
2025-07-15 10:56:39 +00:00
public float CurrentRotationSpeed => currentRotationSpeed;
2025-07-15 10:24:43 +00:00
private float targetSpeed;
private float currentSpeed;
2025-07-15 10:56:39 +00:00
public float CurrentSpeed => currentSpeed;
public float MaxSpeed => maxSpeed;
2025-07-15 10:24:43 +00:00
// 회전 틸트 관련
private float currentRotationTilt;
private float lastRotationY;
private float currentAngularVelocity;
2025-07-15 10:13:50 +00:00
2025-07-15 10:24:43 +00:00
// 가속 틸트 관련
private float currentAccelTilt;
private float accelTiltVelocity;
private float prevSpeed;
// 파도 효과 관련
private float waveTime;
private float waveRandomOffset;
private float currentWaveHeight;
#endregion
#region Unity Messages
2025-07-15 04:02:53 +00:00
private void FixedUpdate()
{
2025-07-15 10:24:43 +00:00
UpdateMovement();
}
#endregion
#region Movement Methods
private void UpdateMovement()
{
if (IsMoving())
2025-07-15 04:02:53 +00:00
{
HandleMovement();
HandleRotation();
}
else
{
2025-07-15 10:24:43 +00:00
DecelerateMovement();
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
2025-07-15 04:02:53 +00:00
ApplyDrag();
ApplyMovement();
2025-07-15 10:24:43 +00:00
}
2025-07-15 04:02:53 +00:00
2025-07-15 10:24:43 +00:00
private bool IsMoving()
{
return currentInput.magnitude > minSpeedThreshold;
}
2025-07-15 04:02:53 +00:00
private void HandleMovement()
{
2025-07-15 10:24:43 +00:00
float baseTargetSpeed = CalculateBaseTargetSpeed();
float turnPenaltyFactor = CalculateTurnPenaltyFactor();
2025-07-15 10:24:43 +00:00
targetSpeed = baseTargetSpeed * turnPenaltyFactor;
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, accelerationRate * Time.fixedDeltaTime);
2025-07-15 04:02:53 +00:00
2025-07-15 10:24:43 +00:00
if (ShouldStop())
2025-07-15 04:02:53 +00:00
{
2025-07-15 10:24:43 +00:00
currentSpeed = 0f;
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
UpdateVelocityVector();
}
2025-07-15 04:02:53 +00:00
private void HandleRotation()
{
2025-07-15 10:24:43 +00:00
if (IsMoving())
2025-07-15 04:02:53 +00:00
{
2025-07-15 10:24:43 +00:00
Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized;
2025-07-15 04:02:53 +00:00
Quaternion targetRotation = Quaternion.LookRotation(inputDirection, Vector3.up);
2025-07-15 10:24:43 +00:00
2025-07-15 04:02:53 +00:00
// 회전 속도를 현재 속도에 비례하도록 설정
2025-07-15 10:24:43 +00:00
float desiredRotationSpeed = rotationSpeed * (currentSpeed / maxSpeed);
2025-07-15 10:13:50 +00:00
desiredRotationSpeed = Mathf.Max(desiredRotationSpeed, minRotationSpeed);
2025-07-15 10:24:43 +00:00
currentRotationSpeed = Mathf.Lerp(currentRotationSpeed, desiredRotationSpeed,
rotationAccelerationRate * Time.fixedDeltaTime);
2025-07-15 04:02:53 +00:00
// 기본 회전 적용 (오브젝트 전체)
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
2025-07-15 10:24:43 +00:00
currentRotationSpeed * Time.fixedDeltaTime
2025-07-15 04:02:53 +00:00
);
}
}
2025-07-15 10:56:39 +00:00
private float CalculateBaseTargetSpeed()
2025-07-15 07:20:02 +00:00
{
2025-07-15 10:56:39 +00:00
return Mathf.Clamp01(currentInput.magnitude) * maxSpeed;
2025-07-15 07:20:02 +00:00
}
2025-07-15 10:56:39 +00:00
private float CalculateTurnPenaltyFactor()
2025-07-15 07:20:02 +00:00
{
2025-07-15 10:56:39 +00:00
Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized;
float angleDifference = Vector3.Angle(transform.forward, inputDirection);
return Mathf.Clamp01(1f - (angleDifference / maxTurnAngle * turnSpeedPenalty));
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:56:39 +00:00
private bool ShouldStop()
{
2025-07-15 10:56:39 +00:00
return currentSpeed < minSpeedThreshold && targetSpeed < minSpeedThreshold;
}
2025-07-15 10:56:39 +00:00
private void UpdateVelocityVector()
{
2025-07-15 10:56:39 +00:00
currentVelocity = transform.forward * currentSpeed;
}
2025-07-15 10:56:39 +00:00
#endregion
2025-07-15 04:02:53 +00:00
private void ApplyDrag()
{
2025-07-15 10:24:43 +00:00
currentSpeed *= dragFactor;
2025-07-15 04:02:53 +00:00
// 최소 속도 이하면 완전히 정지
2025-07-15 10:24:43 +00:00
if (currentSpeed < minSpeedThreshold)
2025-07-15 04:02:53 +00:00
{
2025-07-15 10:24:43 +00:00
currentSpeed = 0f;
2025-07-15 04:02:53 +00:00
}
// 현재 방향으로 감속된 속도 적용
2025-07-15 10:24:43 +00:00
currentVelocity = transform.forward * currentSpeed;
2025-07-15 04:02:53 +00:00
}
private void ApplyMovement()
{
2025-07-15 10:24:43 +00:00
transform.position += currentVelocity * Time.fixedDeltaTime;
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
private void DecelerateMovement()
{
// 입력이 없을 때는 서서히 감속
currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime);
currentRotationSpeed = 0;
}
#region Input Handling
2025-07-15 04:02:53 +00:00
public void OnMove(InputAction.CallbackContext context)
{
2025-07-15 10:24:43 +00:00
currentInput = context.ReadValue<Vector2>();
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
#endregion
}