diff --git a/Assets/0_Voyage/Ship/Player/PlayerShip.prefab b/Assets/0_Voyage/Ship/Player/PlayerShip.prefab index bd2f78a0b..80f5db653 100644 --- a/Assets/0_Voyage/Ship/Player/PlayerShip.prefab +++ b/Assets/0_Voyage/Ship/Player/PlayerShip.prefab @@ -105,6 +105,18 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 2607481b15fd548b18ca4897db56ab3f, type: 3} m_Name: m_EditorClassIdentifier: + maxSpeed: 10 + rotationSpeed: 120 + accelerationRate: 2 + minSpeedThreshold: 0.1 + dragFactor: 0.98 + turnSpeedPenalty: 0.5 + maxTurnAngle: 180 + showDebugLines: 1 + debugLineLength: 4 + debugLineHeightStep: 0.1 + maxTiltAngle: 15 + tiltSpeed: 5 --- !u!1 &6407855916708530114 GameObject: m_ObjectHideFlags: 0 @@ -118,7 +130,7 @@ GameObject: - component: {fileID: 9176830315433650152} - component: {fileID: 8182957266188503550} m_Layer: 0 - m_Name: Sphere + m_Name: Ship_Mesh m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -134,8 +146,8 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 + m_LocalScale: {x: 2, y: 2, z: 2} + m_ConstrainProportionsScale: 1 m_Children: [] m_Father: {fileID: 7177504742663284911} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs b/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs index 90b2eb3dc..00b175307 100644 --- a/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs +++ b/Assets/0_Voyage/_Scripts/Ship/VoyagePlayerShipMovement.cs @@ -3,66 +3,249 @@ using UnityEngine.InputSystem; public class VoyagePlayerShipMovement : MonoBehaviour { - private void Start() - { + [Header("Movement Settings")] + [SerializeField] private float maxSpeed = 10f; + + [SerializeField] private float rotationSpeed = 120f; + [SerializeField] private float accelerationRate = 2f; + [SerializeField] private float minSpeedThreshold = 0.1f; + [SerializeField] private float dragFactor = 0.98f; + + [Header("Turn Settings")] + [SerializeField] private float turnSpeedPenalty = 0.5f; // 선회 시 감속 정도 (0: 감속 없음, 1: 완전 정지) + [SerializeField] private float maxTurnAngle = 180f; // 최대 감속이 적용되는 각도 + + #if UNITY_EDITOR - // 현재 방향을 표시할 LineRenderer 설정 - forwardDirectionLine = CreateLineRenderer("CurrentDirectionLine", Color.green); - upDirectionLine = CreateLineRenderer("upDirectionLine", Color.yellow); - // 입력 방향을 표시할 LineRenderer 설정 - inputDirectionLine = CreateLineRenderer("InputDirectionLine", Color.red); -#endif - } - - public void OnMove(InputAction.CallbackContext context) - { - Vector2 inputVector = context.ReadValue(); - - Vector3 currentForward = transform.forward; - Vector3 currentUp = transform.up; - Vector3 inputDirection = new Vector3(inputVector.x, 0, inputVector.y).normalized; - - - - - -#if UNITY_EDITOR - DrawDebugLine(forwardDirectionLine, currentForward); - DrawDebugLine(upDirectionLine, currentUp); - DrawDebugLine(inputDirectionLine, inputDirection); -#endif - } - - // Debug draw below... -#if UNITY_EDITOR - private LineRenderer inputDirectionLine; + [Header("Debug Settings")] + [SerializeField] private bool showDebugLines = true; + + [SerializeField] private float debugLineLength = 4f; + [SerializeField] private float debugLineHeightStep = 0.1f; + private LineRenderer velocityLine; private LineRenderer forwardDirectionLine; private LineRenderer upDirectionLine; + private LineRenderer inputDirectionLine; + private bool lineRendererCreated = false; +#endif + + private Vector3 currentVelocity; + private Vector2 currentInput; + private float targetSpeed; + private float currentSpeed; + + [Header("Tilt Settings")] + [SerializeField] private float maxTiltAngle = 15f; + [SerializeField] private float tiltSpeed = 5f; + [SerializeField] private string meshObjectName = "Ship_Mesh"; // 메시 오브젝트의 이름 + private Transform meshTransform; // 메시 트랜스폼 + private float currentTilt = 0f; + private Quaternion originalMeshRotation; // 메시의 초기 회전값 저장 + + private void Start() + { + // 하위 오브젝트에서 메시 찾기 + meshTransform = transform.Find(meshObjectName); + if (meshTransform == null) + { + Debug.LogError($"메시 오브젝트를 찾을 수 없습니다: {meshObjectName}"); + return; + } + + // 메시의 초기 회전값 저장 + originalMeshRotation = meshTransform.localRotation; + } + + private void FixedUpdate() + { + if (currentInput.magnitude > minSpeedThreshold) + { + HandleMovement(); + HandleRotation(); + } + else + { + // 입력이 없을 때는 서서히 감속 + currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime); + } + + ApplyDrag(); + ApplyMovement(); + +#if UNITY_EDITOR + if (showDebugLines) + { + UpdateAllDebugLines(); + } +#endif + } + + + private void HandleMovement() + { + // 기본 목표 속도 계산 (입력 크기에 비례) + float baseTargetSpeed = Mathf.Clamp01(currentInput.magnitude) * maxSpeed; + + // 현재 방향과 목표 방향 사이의 각도 계산 + Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized; + float angleDifference = Vector3.Angle(transform.forward, inputDirection); + + // 각도에 따른 속도 페널티 계산 (각도가 클수록 더 큰 감속) + float turnPenaltyFactor = 1f - (angleDifference / maxTurnAngle * turnSpeedPenalty); + turnPenaltyFactor = Mathf.Clamp01(turnPenaltyFactor); + + // 최종 목표 속도 계산 (기본 속도에 선회 페널티 적용) + targetSpeed = baseTargetSpeed * turnPenaltyFactor; + + // 현재 속도를 목표 속도로 부드럽게 보간 + currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, accelerationRate * Time.fixedDeltaTime); + + // 최소 임계값 이하면 완전히 정지 + if (currentSpeed < minSpeedThreshold && targetSpeed < minSpeedThreshold) + { + currentSpeed = 0f; + } + + // 현재 바라보는 방향으로 속도 벡터 업데이트 + currentVelocity = transform.forward * currentSpeed; + } + + private void HandleRotation() + { + if (currentInput.magnitude > minSpeedThreshold) + { + Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized; + Quaternion targetRotation = Quaternion.LookRotation(inputDirection, Vector3.up); + + // 회전 속도를 현재 속도에 비례하도록 설정 + float currentRotationSpeed = rotationSpeed * (currentSpeed / maxSpeed); + 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, + targetRotation, + 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 ApplyDrag() + { + currentSpeed *= dragFactor; + + // 최소 속도 이하면 완전히 정지 + if (currentSpeed < minSpeedThreshold) + { + currentSpeed = 0f; + } + + // 현재 방향으로 감속된 속도 적용 + currentVelocity = transform.forward * currentSpeed; + } + + + private void ApplyMovement() + { + transform.position += currentVelocity * Time.fixedDeltaTime; + } + + public void OnMove(InputAction.CallbackContext context) + { + currentInput = context.ReadValue(); + // Debug Log this + Debug.Log(currentInput); + } + +#if UNITY_EDITOR + private void UpdateAllDebugLines() + { + if (lineRendererCreated == false) + { + lineRendererCreated = true; + forwardDirectionLine = CreateLineRenderer("CurrentDirectionLine", Color.green); + upDirectionLine = CreateLineRenderer("UpDirectionLine", Color.yellow); + inputDirectionLine = CreateLineRenderer("InputDirectionLine", Color.red); + velocityLine = CreateLineRenderer("VelocityLine", Color.blue); + } + + // 전방 방향 표시 (기본 높이) + DrawDebugLine(forwardDirectionLine, transform.forward, debugLineLength, 0); + + // 메시의 위쪽 방향 표시 (틸팅 반영) + if (meshTransform is not null) + { + DrawDebugLine(upDirectionLine, meshTransform.up, debugLineLength, debugLineHeightStep); + } + + // 입력 방향 표시 (두 단계 위) + Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized; + DrawDebugLine(inputDirectionLine, inputDirection, debugLineLength * currentInput.magnitude, debugLineHeightStep * 2); + + // 속도 벡터 표시 (세 단계 위) + DrawDebugLine(velocityLine, currentVelocity.normalized, currentVelocity.magnitude, debugLineHeightStep * 3); + } + private LineRenderer CreateLineRenderer(string name, Color color) { GameObject lineObj = new GameObject(name); lineObj.transform.SetParent(transform); LineRenderer line = lineObj.AddComponent(); - // LineRenderer 기본 설정 line.startWidth = 0.1f; line.endWidth = 0.1f; line.material = new Material(Shader.Find("Universal Render Pipeline/Unlit")); line.startColor = color; line.endColor = color; line.positionCount = 2; - + + // 라인 렌더러가 다른 오브젝트를 가리지 않도록 설정 + line.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + line.receiveShadows = false; line.material.color = color; return line; } - private void DrawDebugLine(LineRenderer renderer, Vector3 direction) + + private void DrawDebugLine(LineRenderer renderer, Vector3 direction, float length, float heightOffset) { - const float lineLength = 4; - Vector3 position = transform.position; - // 현재 방향 라인 업데이트 (파란색) + if (!renderer) return; + + Vector3 position = transform.position + Vector3.up * heightOffset; renderer.SetPosition(0, position); - renderer.SetPosition(1, position + direction * lineLength); + renderer.SetPosition(1, position + direction * length); } #endif + + private void OnValidate() + { + // 에디터에서 메시 오브젝트 이름이 변경될 때 자동으로 찾기 + if (Application.isEditor && !Application.isPlaying) + { + meshTransform = transform.Find(meshObjectName); + } + } } \ No newline at end of file diff --git a/Assets/ShipTest/Ship.mat b/Assets/ShipTest/Ship.mat index 30a938d19..7f13e33e1 100644 --- a/Assets/ShipTest/Ship.mat +++ b/Assets/ShipTest/Ship.mat @@ -33,7 +33,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _BaseMap: - m_Texture: {fileID: 2800000, guid: 9fab180d66628484a9bf08ce8bbd51c8, type: 3} + m_Texture: {fileID: 2800000, guid: b28a01dbcbf8f0c4c8b70e10b99d5a28, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _BlendTex: