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

209 lines
5.7 KiB
C#
Raw Normal View History

using UnityEngine;
using UnityEngine.InputSystem;
2025-07-15 10:24:43 +00:00
/// <summary>
2025-07-15 11:10:46 +00:00
/// 플레이어 배의 기본 이동과 회전을 처리하는 컴포넌트
2025-07-15 10:24:43 +00:00
/// </summary>
2025-07-15 11:10:46 +00:00
[RequireComponent(typeof(Rigidbody))]
public class VoyagePlayerShipMovement : MonoBehaviour
{
2025-07-15 11:10:46 +00:00
#region Settings
[System.Serializable]
public class MovementSettings
{
[Tooltip("배의 최대 이동 속도")]
public float maxSpeed = 20f;
public float accelerationRate = 1f;
public float dragFactor = 0.98f;
public float minSpeedThreshold = 0.1f;
}
2025-07-15 10:24:43 +00:00
2025-07-15 11:10:46 +00:00
[System.Serializable]
public class RotationSettings
{
public float maxRotationSpeed = 270f;
public float minRotationSpeed = 90f;
public float accelerationRate = 5f;
[Tooltip("선회 시 감속 정도 (0: 감속 없음, 1: 완전 정지)")]
public float turnSpeedPenalty = 0.5f;
[Tooltip("최대 감속이 적용되는 각도")]
public float maxTurnAngle = 180f;
}
#endregion
#region Inspector Fields
[SerializeField]
private MovementSettings movementSettings = new();
2025-07-15 10:56:39 +00:00
2025-07-15 11:10:46 +00:00
[SerializeField]
private RotationSettings rotationSettings = new();
2025-07-15 10:24:43 +00:00
#endregion
2025-07-15 11:10:46 +00:00
#region Properties
public Vector2 CurrentInput => currentInput;
public float CurrentRotationSpeed => currentRotationSpeed;
public float CurrentSpeed => currentSpeed;
public float MaxSpeed => movementSettings.maxSpeed;
public Vector3 CurrentVelocity => currentVelocity;
#endregion
2025-07-15 10:24:43 +00:00
2025-07-15 11:10:46 +00:00
#region Private Fields
2025-07-15 10:24:43 +00:00
private Vector3 currentVelocity;
private Vector2 currentInput;
private float currentRotationSpeed;
private float targetSpeed;
private float currentSpeed;
#endregion
#region Unity Messages
2025-07-15 04:02:53 +00:00
private void FixedUpdate()
{
2025-07-15 11:10:46 +00:00
UpdateShipMovement();
}
#endregion
#region Public Methods
public void OnMove(InputAction.CallbackContext context)
{
currentInput = context.ReadValue<Vector2>();
2025-07-15 10:24:43 +00:00
}
#endregion
#region Movement Methods
2025-07-15 11:10:46 +00:00
private void UpdateShipMovement()
2025-07-15 10:24:43 +00:00
{
if (IsMoving())
2025-07-15 04:02:53 +00:00
{
2025-07-15 11:10:46 +00:00
UpdateMovementWithInput();
2025-07-15 04:02:53 +00:00
}
else
{
2025-07-15 11:10:46 +00:00
DecelerateShip();
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
2025-07-15 11:10:46 +00:00
ApplyDragForce();
ApplyFinalMovement();
2025-07-15 10:24:43 +00:00
}
2025-07-15 04:02:53 +00:00
2025-07-15 11:10:46 +00:00
private void UpdateMovementWithInput()
2025-07-15 10:24:43 +00:00
{
2025-07-15 11:10:46 +00:00
UpdateSpeed();
UpdateRotation();
}
2025-07-15 04:02:53 +00:00
2025-07-15 11:10:46 +00:00
private void UpdateSpeed()
{
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;
2025-07-15 11:10:46 +00:00
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed,
movementSettings.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 11:10:46 +00:00
StopShip();
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
UpdateVelocityVector();
}
2025-07-15 11:10:46 +00:00
private void UpdateRotation()
2025-07-15 04:02:53 +00:00
{
2025-07-15 11:10:46 +00:00
if (!IsMoving()) return;
Quaternion targetRotation = CalculateTargetRotation();
float rotationSpeed = CalculateRotationSpeed();
ApplyRotation(targetRotation, rotationSpeed);
}
2025-07-15 11:10:46 +00:00
#endregion
#region Helper Methods
private bool IsMoving()
{
return currentInput.magnitude > movementSettings.minSpeedThreshold;
}
2025-07-15 10:56:39 +00:00
private float CalculateBaseTargetSpeed()
2025-07-15 07:20:02 +00:00
{
2025-07-15 11:10:46 +00:00
return Mathf.Clamp01(currentInput.magnitude) * movementSettings.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);
2025-07-15 11:10:46 +00:00
float penaltyFactor = angleDifference / rotationSettings.maxTurnAngle * rotationSettings.turnSpeedPenalty;
return Mathf.Clamp01(1f - penaltyFactor);
2025-07-15 04:02:53 +00:00
}
2025-07-15 11:10:46 +00:00
private Quaternion CalculateTargetRotation()
{
2025-07-15 11:10:46 +00:00
Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized;
return Quaternion.LookRotation(inputDirection, Vector3.up);
}
2025-07-15 11:10:46 +00:00
private float CalculateRotationSpeed()
{
2025-07-15 11:10:46 +00:00
float speedBasedRotation = rotationSettings.maxRotationSpeed * (currentSpeed / movementSettings.maxSpeed);
float desiredRotationSpeed = Mathf.Max(speedBasedRotation, rotationSettings.minRotationSpeed);
return Mathf.Lerp(currentRotationSpeed, desiredRotationSpeed,
rotationSettings.accelerationRate * Time.fixedDeltaTime);
}
2025-07-15 11:10:46 +00:00
private void ApplyRotation(Quaternion targetRotation, float rotationSpeed)
2025-07-15 04:02:53 +00:00
{
2025-07-15 11:10:46 +00:00
currentRotationSpeed = rotationSpeed;
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
rotationSpeed * Time.fixedDeltaTime
);
}
2025-07-15 04:02:53 +00:00
2025-07-15 11:10:46 +00:00
private bool ShouldStop()
{
return currentSpeed < movementSettings.minSpeedThreshold &&
targetSpeed < movementSettings.minSpeedThreshold;
}
2025-07-15 04:02:53 +00:00
2025-07-15 11:10:46 +00:00
private void StopShip()
{
currentSpeed = 0f;
currentVelocity = Vector3.zero;
}
private void UpdateVelocityVector()
{
2025-07-15 10:24:43 +00:00
currentVelocity = transform.forward * currentSpeed;
2025-07-15 04:02:53 +00:00
}
2025-07-15 11:10:46 +00:00
private void DecelerateShip()
2025-07-15 04:02:53 +00:00
{
2025-07-15 11:10:46 +00:00
currentSpeed = Mathf.Lerp(currentSpeed, 0f,
movementSettings.accelerationRate * Time.fixedDeltaTime);
currentRotationSpeed = 0f;
2025-07-15 04:02:53 +00:00
}
2025-07-15 11:10:46 +00:00
private void ApplyDragForce()
2025-07-15 10:24:43 +00:00
{
2025-07-15 11:10:46 +00:00
currentSpeed *= movementSettings.dragFactor;
if (currentSpeed < movementSettings.minSpeedThreshold)
{
StopShip();
}
else
{
UpdateVelocityVector();
}
2025-07-15 10:24:43 +00:00
}
2025-07-15 11:10:46 +00:00
private void ApplyFinalMovement()
2025-07-15 04:02:53 +00:00
{
2025-07-15 11:10:46 +00:00
transform.position += currentVelocity * Time.fixedDeltaTime;
2025-07-15 04:02:53 +00:00
}
2025-07-15 10:24:43 +00:00
#endregion
}