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