DDD-43 코드 리팩토링

This commit is contained in:
Jeonghyeon Ha 2025-07-15 19:24:43 +09:00
parent d03a4b7892
commit ccf8772ccd
2 changed files with 388 additions and 315 deletions

View File

@ -106,17 +106,17 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
maxSpeed: 20
rotationSpeed: 180
minRotationSpeed: 60
rotationAccelerationRate: 5
accelerationRate: 1
minSpeedThreshold: 0.1
dragFactor: 0.98
minSpeedThreshold: 0.1
rotationSpeed: 270
minRotationSpeed: 90
rotationAccelerationRate: 5
turnSpeedPenalty: 0.5
maxTurnAngle: 180
maxRotationTiltAngle: 15
rotationTiltSpeed: 5
RotationTiltReturnSpeed: 3
rotationTiltReturnSpeed: 3
angularVelocityMultiplier: 2
maxAccelTiltAngle: 15
accelTiltForce: 15
@ -130,7 +130,7 @@ MonoBehaviour:
speedWaveMultiplier: 5
randomWaveOffset: 0.5
waveUnitSpeed: 10
meshObjectName: Ship_Mesh
meshTransform: {fileID: 2507610487897935131}
showDebugVisuals: 1
debugLineLength: 5
debugLineWidth: 0.1

View File

@ -1,87 +1,90 @@
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;
/// <summary>
/// 플레이어 배의 움직임을 제어하는 컴포넌트
/// 속도, 회전, 틸트, 파도 효과 등을 관리합니다.
/// </summary>
public class VoyagePlayerShipMovement : MonoBehaviour
{
[Header("Movement Settings")]
#region Inspector Fields
[Header("기본 이동 설정")]
[Tooltip("배의 최대 이동 속도")]
[SerializeField] private float maxSpeed = 20f;
[SerializeField] private float rotationSpeed = 180f;
[SerializeField] private float minRotationSpeed = 60f;
[SerializeField] private float rotationAccelerationRate = 5f;
[SerializeField] private float accelerationRate = 1f;
[SerializeField] private float minSpeedThreshold = 0.1f;
[SerializeField] private float dragFactor = 0.98f;
private Vector3 _currentVelocity;
private Vector2 _currentInput;
private float _currentRotationSpeed;
private float _targetSpeed;
private float _currentSpeed;
[SerializeField] private float minSpeedThreshold = 0.1f;
[Header("Turn Settings")]
[SerializeField] private float turnSpeedPenalty = 0.5f; // 선회 시 감속 정도 (0: 감속 없음, 1: 완전 정지)
[SerializeField] private float maxTurnAngle = 180f; // 최대 감속이 적용되는 각도
[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;
// Rotation Tilt
[Header("Rotation Tilt Settings")]
[Header("회전 틸트 설정")]
[SerializeField] private float maxRotationTiltAngle = 15f;
[SerializeField] private float rotationTiltSpeed = 5f;
[SerializeField] private float RotationTiltReturnSpeed = 3f; // 원래 자세로 돌아오는 속도
[SerializeField] private float angularVelocityMultiplier = 2f; // 각속도 영향력
private float _currentRotationTilt = 0f;
private float _lastRotationY; // 이전 프레임의 Y축 회전값
private float _currentAngularVelocity; // 현재 각속도
[SerializeField] private float rotationTiltReturnSpeed = 3f;
[SerializeField] private float angularVelocityMultiplier = 2f;
// Acceleration Tilt
[Header("Acceleration Tilt Settings")]
[SerializeField] private float maxAccelTiltAngle = 15f; // 최대 가속 틸트 각도
[SerializeField] private float accelTiltForce = 15f; // 틸트 강도
[SerializeField] private float accelTiltDamping = 0.9f; // 틸트 감쇠 계수
[SerializeField] private float accelTiltSpeed = 10f; // 스프링 보간속도
[SerializeField] private float springStiffness = 30f; // 스프링 강성
[SerializeField] private float springDamping = 15f; // 스프링 감쇠
private float _currentAccelTilt;
private float _accelTiltVelocity;
private float _prevSpeed;
[Header("가속 틸트 설정")]
[SerializeField] private float maxAccelTiltAngle = 15f;
[SerializeField] private float accelTiltForce = 15f;
[SerializeField] private float accelTiltDamping = 0.9f;
[SerializeField] private float accelTiltSpeed = 10f;
[SerializeField] private float springStiffness = 30f;
[SerializeField] private float springDamping = 15f;
// Wave offset
[Header("Wave Settings")]
[SerializeField] private float minSpeedWaveHeight = 0.2f; // 기본 파도 높이
[SerializeField] private float maxSpeedWaveHeight = 0.05f; // 기준 속력일때 파도 높이
[Header("파도 효과 설정")]
[SerializeField] private float minSpeedWaveHeight = 0.2f;
[SerializeField] private float maxSpeedWaveHeight = 0.05f;
[SerializeField] private float baseWaveFrequency = 1f;
[SerializeField] private float speedWaveMultiplier = 5f;
[SerializeField] private float randomWaveOffset = 0.5f;
[SerializeField] private float waveUnitSpeed = 10f;
[SerializeField] private float baseWaveFrequency = 1f; // 기본 파도 주기
[SerializeField] private float speedWaveMultiplier = 5f; // 속도에 따른 주기 증가 계수
[SerializeField] private float randomWaveOffset = 0.5f; // 랜덤 오프셋 범위
[SerializeField] private float waveUnitSpeed = 10f; // 기준 속력
private float _waveTime;
private float _waveRandomOffset;
private float _currentWaveHeight;
[Header("메시 설정")]
[SerializeField] private Transform meshTransform;
#endregion
[Header("Mesh Settings")]
[SerializeField] private string meshObjectName = "Ship_Mesh";
private Transform _meshTransform;
#region Private Fields
private Vector3 currentVelocity;
private Vector2 currentInput;
private float currentRotationSpeed;
private float targetSpeed;
private float currentSpeed;
private Quaternion _originalMeshRotation;
private Vector3 _originalMeshPosition;
// 회전 틸트 관련
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;
// 메시 원본 상태
private Quaternion originalMeshRotation;
private Vector3 originalMeshPosition;
#endregion
#region Unity Messages
private void Start()
{
_meshTransform = transform.Find(meshObjectName);
if (_meshTransform == null)
{
Debug.LogError($"메시 오브젝트를 찾을 수 없습니다: {meshObjectName}");
enabled = false;
return;
}
_originalMeshPosition = _meshTransform.localPosition;
_originalMeshRotation = _meshTransform.localRotation;
_lastRotationY = transform.eulerAngles.y;
_waveTime = 0f;
_waveRandomOffset = Random.Range(-randomWaveOffset, randomWaveOffset);
InitializeMeshTransform();
InitializeWaveEffect();
#if UNITY_EDITOR
InitializeDebugVisuals();
#endif
@ -89,118 +92,154 @@ public class VoyagePlayerShipMovement : MonoBehaviour
private void FixedUpdate()
{
if (_currentInput.magnitude > minSpeedThreshold)
UpdateMovement();
UpdateVisualEffects();
#if UNITY_EDITOR
UpdateDebugVisuals();
#endif
}
private void OnValidate()
{
ValidateMeshTransform();
}
#endregion
#region Movement Methods
private void UpdateMovement()
{
if (IsMoving())
{
HandleMovement();
HandleRotation();
}
else
{
// 입력이 없을 때는 서서히 감속
_currentSpeed = Mathf.Lerp(_currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime);
_currentRotationSpeed = 0;
DecelerateMovement();
}
ApplyDrag();
ApplyMovement();
}
// Cosmetic mesh tilting
UpdateMeshRotationTilt();
UpdateAccelerationTilt();
ApplyMeshTilt();
// Cosmetic mesh wave offset
UpdateWaveMotion();
ApplyMeshOffset();
#if UNITY_EDITOR
UpdateDebugVisuals();
#endif
private bool IsMoving()
{
return currentInput.magnitude > minSpeedThreshold;
}
private void HandleMovement()
{
// 기본 목표 속도 계산 (입력 크기에 비례)
float baseTargetSpeed = Mathf.Clamp01(_currentInput.magnitude) * maxSpeed;
float baseTargetSpeed = CalculateBaseTargetSpeed();
float turnPenaltyFactor = CalculateTurnPenaltyFactor();
// 현재 방향과 목표 방향 사이의 각도 계산
Vector3 inputDirection = new Vector3(_currentInput.x, 0, _currentInput.y).normalized;
float angleDifference = Vector3.Angle(transform.forward, inputDirection);
targetSpeed = baseTargetSpeed * turnPenaltyFactor;
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, accelerationRate * Time.fixedDeltaTime);
// 각도에 따른 속도 페널티 계산 (각도가 클수록 더 큰 감속)
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)
if (ShouldStop())
{
_currentSpeed = 0f;
currentSpeed = 0f;
}
// 현재 바라보는 방향으로 속도 벡터 업데이트
_currentVelocity = transform.forward * _currentSpeed;
UpdateVelocityVector();
}
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
#region Visual Effects
private void UpdateVisualEffects()
{
if (meshTransform is null) return;
UpdateMeshRotationTilt();
UpdateAccelerationTilt();
ApplyMeshTilt();
UpdateWaveMotion();
ApplyMeshOffset();
}
private void HandleRotation()
{
if (_currentInput.magnitude > minSpeedThreshold)
if (IsMoving())
{
Vector3 inputDirection = new Vector3(_currentInput.x, 0, _currentInput.y).normalized;
Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized;
Quaternion targetRotation = Quaternion.LookRotation(inputDirection, Vector3.up);
// 회전 속도를 현재 속도에 비례하도록 설정
float desiredRotationSpeed = rotationSpeed * (_currentSpeed / maxSpeed);
float desiredRotationSpeed = rotationSpeed * (currentSpeed / maxSpeed);
desiredRotationSpeed = Mathf.Max(desiredRotationSpeed, minRotationSpeed);
_currentRotationSpeed = Mathf.Lerp(_currentRotationSpeed, desiredRotationSpeed, rotationAccelerationRate * Time.fixedDeltaTime);
currentRotationSpeed = Mathf.Lerp(currentRotationSpeed, desiredRotationSpeed,
rotationAccelerationRate * Time.fixedDeltaTime);
// 기본 회전 적용 (오브젝트 전체)
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
_currentRotationSpeed * Time.fixedDeltaTime
currentRotationSpeed * Time.fixedDeltaTime
);
}
}
private void UpdateMeshRotationTilt()
{
if (_meshTransform is null) return;
if (meshTransform is null) return;
// 현재 Y축 회전값과 각속도 계산
float currentRotationY = transform.eulerAngles.y;
float deltaRotation = Mathf.DeltaAngle(_lastRotationY, currentRotationY);
_currentAngularVelocity = deltaRotation / Time.fixedDeltaTime;
float deltaRotation = Mathf.DeltaAngle(lastRotationY, currentRotationY);
currentAngularVelocity = deltaRotation / Time.fixedDeltaTime;
// 목표 틸트 각도 계산
float targetTilt = -_currentAngularVelocity * angularVelocityMultiplier;
float targetTilt = -currentAngularVelocity * angularVelocityMultiplier;
targetTilt = Mathf.Clamp(targetTilt, -maxRotationTiltAngle, maxRotationTiltAngle);
// 틸트 적용 또는 복귀
if (Mathf.Abs(_currentAngularVelocity) > 0.1f)
if (Mathf.Abs(currentAngularVelocity) > 0.1f)
{
_currentRotationTilt = Mathf.Lerp(_currentRotationTilt, targetTilt, rotationTiltSpeed * Time.fixedDeltaTime);
currentRotationTilt =
Mathf.Lerp(currentRotationTilt, targetTilt, rotationTiltSpeed * Time.fixedDeltaTime);
}
else
{
// 입력이 없을 때는 원래 자세로 천천히 복귀
_currentRotationTilt = Mathf.Lerp(_currentRotationTilt, 0f, RotationTiltReturnSpeed * Time.fixedDeltaTime);
currentRotationTilt = Mathf.Lerp(currentRotationTilt, 0f, rotationTiltReturnSpeed * Time.fixedDeltaTime);
}
_lastRotationY = currentRotationY;
lastRotationY = currentRotationY;
}
private void UpdateAccelerationTilt()
{
// 가속도 계산
float acceleration = (_currentSpeed - _prevSpeed) / Time.fixedDeltaTime;
float acceleration = (currentSpeed - prevSpeed) / Time.fixedDeltaTime;
// 스프링 물리 시스템 구현
float springForce = -springStiffness * _currentAccelTilt; // 복원력
float dampingForce = -springDamping * _accelTiltVelocity; // 감쇠력
float springForce = -springStiffness * currentAccelTilt; // 복원력
float dampingForce = -springDamping * accelTiltVelocity; // 감쇠력
float accelerationForce = -acceleration * accelTiltForce; // 가속에 의한 힘
// 전체 힘 계산
@ -210,90 +249,127 @@ public class VoyagePlayerShipMovement : MonoBehaviour
float tiltAcceleration = totalForce;
// 속도 업데이트
_accelTiltVelocity += tiltAcceleration;
_accelTiltVelocity *= accelTiltDamping; // 감쇠 적용
_accelTiltVelocity *= Time.fixedDeltaTime;
accelTiltVelocity += tiltAcceleration;
accelTiltVelocity *= accelTiltDamping; // 감쇠 적용
accelTiltVelocity *= Time.fixedDeltaTime;
// 위치(각도) 업데이트
_currentAccelTilt = Mathf.Lerp(_currentAccelTilt, _currentAccelTilt + _accelTiltVelocity, accelTiltSpeed * Time.fixedDeltaTime);
_currentAccelTilt = Mathf.Clamp(_currentAccelTilt, -maxAccelTiltAngle, maxAccelTiltAngle);
currentAccelTilt = Mathf.Lerp(currentAccelTilt, currentAccelTilt + accelTiltVelocity,
accelTiltSpeed * Time.fixedDeltaTime);
currentAccelTilt = Mathf.Clamp(currentAccelTilt, -maxAccelTiltAngle, maxAccelTiltAngle);
_prevSpeed = _currentSpeed;
prevSpeed = currentSpeed;
}
private void ApplyMeshTilt()
{
if (_meshTransform is null) return;
if (meshTransform is null) return;
// 회전 틸트와 가속 틸트를 조합
// 메시에 최종 틸트 적용
_meshTransform.localRotation = _originalMeshRotation * Quaternion.Euler(
_currentAccelTilt, // X축 (가속 틸트)
meshTransform.localRotation = originalMeshRotation * Quaternion.Euler(
currentAccelTilt, // X축 (가속 틸트)
0, // Y축
_currentRotationTilt // Z축 (회전 틸트)
currentRotationTilt // Z축 (회전 틸트)
);
}
private void UpdateWaveMotion()
{
if (_meshTransform is null) return;
if (meshTransform is null) return;
// 현재 속도에 비례하여 파도 주기 조절
float waveSpeedFactor = 1f + (_currentSpeed / waveUnitSpeed) * speedWaveMultiplier;
_waveTime += Time.fixedDeltaTime * baseWaveFrequency * waveSpeedFactor;
float currentSpeedByUnit = _currentSpeed / waveUnitSpeed;
float waveSpeedFactor = 1f + (currentSpeed / waveUnitSpeed) * speedWaveMultiplier;
waveTime += Time.fixedDeltaTime * baseWaveFrequency * waveSpeedFactor;
float currentSpeedByUnit = currentSpeed / waveUnitSpeed;
currentSpeedByUnit = Mathf.Clamp01(currentSpeedByUnit);
float waveHeight = Mathf.Lerp(minSpeedWaveHeight, maxSpeedWaveHeight, currentSpeedByUnit);
_currentWaveHeight = waveHeight * Mathf.Sin(_waveTime + _waveRandomOffset);
currentWaveHeight = waveHeight * Mathf.Sin(waveTime + waveRandomOffset);
}
private void ApplyMeshOffset()
{
if (_meshTransform is null) return;
if (meshTransform is null) return;
Vector3 position = _originalMeshPosition + (Vector3.up * _currentWaveHeight);
_meshTransform.localPosition = position;
Vector3 position = originalMeshPosition + (Vector3.up * currentWaveHeight);
meshTransform.localPosition = position;
}
private void ApplyDrag()
{
_currentSpeed *= dragFactor;
currentSpeed *= dragFactor;
// 최소 속도 이하면 완전히 정지
if (_currentSpeed < minSpeedThreshold)
if (currentSpeed < minSpeedThreshold)
{
_currentSpeed = 0f;
currentSpeed = 0f;
}
// 현재 방향으로 감속된 속도 적용
_currentVelocity = transform.forward * _currentSpeed;
currentVelocity = transform.forward * currentSpeed;
}
private void ApplyMovement()
{
transform.position += _currentVelocity * Time.fixedDeltaTime;
transform.position += currentVelocity * Time.fixedDeltaTime;
}
private void DecelerateMovement()
{
// 입력이 없을 때는 서서히 감속
currentSpeed = Mathf.Lerp(currentSpeed, 0f, accelerationRate * Time.fixedDeltaTime);
currentRotationSpeed = 0;
}
#endregion
#region Input Handling
public void OnMove(InputAction.CallbackContext context)
{
_currentInput = context.ReadValue<Vector2>();
currentInput = context.ReadValue<Vector2>();
}
private void OnValidate()
#endregion
#region Initialization
private void InitializeMeshTransform()
{
// 에디터에서 메시 오브젝트 이름이 변경될 때 자동으로 찾기
if (Application.isEditor && !Application.isPlaying)
if (meshTransform is null)
{
_meshTransform = transform.Find(meshObjectName);
Debug.LogError("Mesh Transform이 할당되지 않았습니다.");
enabled = false;
return;
}
originalMeshPosition = meshTransform.localPosition;
originalMeshRotation = meshTransform.localRotation;
lastRotationY = transform.eulerAngles.y;
}
private void InitializeWaveEffect()
{
waveTime = 0f;
waveRandomOffset = Random.Range(-randomWaveOffset, randomWaveOffset);
}
private void ValidateMeshTransform()
{
if (Application.isEditor && !Application.isPlaying && meshTransform is null)
{
Debug.LogWarning("Mesh Transform을 Inspector에서 할당해주세요.");
}
}
#endregion
#if UNITY_EDITOR
[Header("Debug Visualization")]
[SerializeField] private bool showDebugVisuals = true;
[SerializeField] private float debugLineLength = 5f;
[SerializeField] private float debugLineWidth = 0.1f;
@ -304,173 +380,170 @@ public class VoyagePlayerShipMovement : MonoBehaviour
private LineRenderer _waveHeightLineRenderer;
private LineRenderer _wavePatternLineRenderer;
private void InitializeDebugVisuals()
{
if (!showDebugVisuals) return;
// 속도 표시
_speedLineRenderer = CreateLineRenderer("SpeedLine", Color.green);
// 회전 방향 표시
_rotationSpeedLineRenderer = CreateLineRenderer("RotationSpeedLine", Color.magenta);
// 회전 방향 표시
_rotationDeltaLineRenderer = CreateLineRenderer("RotationDeltaLine", Color.yellow);
// 틸트 표시
_TiltLineRenderer = CreateLineRenderer("TiltLine", Color.red);
// 파도 높이 표시
_waveHeightLineRenderer = CreateLineRenderer("WaveHeightLine", Color.blue);
// 파도 패턴 표시
_wavePatternLineRenderer = CreateLineRenderer("WavePatternLine", Color.cyan);
_wavePatternLineRenderer.positionCount = 50; // 파도 패턴을 위한 더 많은 점
}
private void UpdateDebugVisuals()
{
if (!showDebugVisuals) return;
// 속도 벡터 표시
UpdateSpeedLine();
// 회전 방향 및 각속도 표시
UpdateRotationSpeedLine();
UpdateRotationDeltaLine();
// 회전 틸트 표시
UpdateTiltLine();
// 파도 높이와 패턴 표시
UpdateWaveVisualization();
}
private void UpdateSpeedLine()
{
Vector3 start = transform.position + Vector3.up * 1.5f;
Vector3 end = start + transform.forward * (_currentSpeed / maxSpeed) * debugLineLength * 2;
DrawLine(_speedLineRenderer, start, end);
}
private void UpdateRotationSpeedLine()
{
Vector3 start = transform.position + Vector3.up * 1.2f;
// 각속도를 호로 표현
if (Mathf.Abs(_currentRotationSpeed) > 0.1f)
private void InitializeDebugVisuals()
{
Vector3[] arcPoints = new Vector3[10];
float radius = debugLineLength * 1f;
float angleStep = _currentRotationSpeed * 1f / (arcPoints.Length - 1);
if (!showDebugVisuals) return;
for (int i = 0; i < arcPoints.Length; i++)
// 속도 표시
_speedLineRenderer = CreateLineRenderer("SpeedLine", Color.green);
// 회전 방향 표시
_rotationSpeedLineRenderer = CreateLineRenderer("RotationSpeedLine", Color.magenta);
// 회전 방향 표시
_rotationDeltaLineRenderer = CreateLineRenderer("RotationDeltaLine", Color.yellow);
// 틸트 표시
_TiltLineRenderer = CreateLineRenderer("TiltLine", Color.red);
// 파도 높이 표시
_waveHeightLineRenderer = CreateLineRenderer("WaveHeightLine", Color.blue);
// 파도 패턴 표시
_wavePatternLineRenderer = CreateLineRenderer("WavePatternLine", Color.cyan);
_wavePatternLineRenderer.positionCount = 50; // 파도 패턴을 위한 더 많은 점
}
private void UpdateDebugVisuals()
{
if (!showDebugVisuals) return;
// 속도 벡터 표시
UpdateSpeedLine();
// 회전 방향 및 각속도 표시
UpdateRotationSpeedLine();
UpdateRotationDeltaLine();
// 회전 틸트 표시
UpdateTiltLine();
// 파도 높이와 패턴 표시
UpdateWaveVisualization();
}
private void UpdateSpeedLine()
{
Vector3 start = transform.position + Vector3.up * 1.5f;
Vector3 end = start + transform.forward * (currentSpeed / maxSpeed) * debugLineLength * 2;
DrawLine(_speedLineRenderer, start, end);
}
private void UpdateRotationSpeedLine()
{
Vector3 start = transform.position + Vector3.up * 1.2f;
// 각속도를 호로 표현
if (Mathf.Abs(currentRotationSpeed) > 0.1f)
{
float angle = angleStep * i;
Vector3 point = start + Quaternion.Euler(0, angle, 0) * transform.forward * radius;
arcPoints[i] = point;
Vector3[] arcPoints = new Vector3[10];
float radius = debugLineLength * 1f;
float angleStep = currentRotationSpeed * 1f / (arcPoints.Length - 1);
for (int i = 0; i < arcPoints.Length; i++)
{
float angle = angleStep * i;
Vector3 point = start + Quaternion.Euler(0, angle, 0) * transform.forward * radius;
arcPoints[i] = point;
}
_rotationSpeedLineRenderer.positionCount = arcPoints.Length;
_rotationSpeedLineRenderer.SetPositions(arcPoints);
}
else
{
_rotationSpeedLineRenderer.positionCount = 0;
}
}
private void UpdateRotationDeltaLine()
{
float deltaAngle = 0f;
if (currentInput.magnitude > minSpeedThreshold)
{
Vector3 inputDirection = new Vector3(currentInput.x, 0, currentInput.y).normalized;
Quaternion targetRotation = Quaternion.LookRotation(inputDirection, Vector3.up);
deltaAngle = Quaternion.Angle(transform.rotation, targetRotation);
}
_rotationSpeedLineRenderer.positionCount = arcPoints.Length;
_rotationSpeedLineRenderer.SetPositions(arcPoints);
}
else
{
_rotationSpeedLineRenderer.positionCount = 0;
}
}
private void UpdateRotationDeltaLine()
{
float deltaAngle = 0f;
if (_currentInput.magnitude > minSpeedThreshold)
{
Vector3 inputDirection = new Vector3(_currentInput.x, 0, _currentInput.y).normalized;
Quaternion targetRotation = Quaternion.LookRotation(inputDirection, Vector3.up);
deltaAngle = Quaternion.Angle(transform.rotation, targetRotation);
}
Vector3 start = transform.position + Vector3.up * 1.2f;
// 각속도를 호로 표현
if (Mathf.Abs(deltaAngle) > 0.1f)
{
Vector3[] arcPoints = new Vector3[10];
float radius = debugLineLength * 1.05f;
float angleStep = deltaAngle * 1f / (arcPoints.Length - 1);
for (int i = 0; i < arcPoints.Length; i++)
Vector3 start = transform.position + Vector3.up * 1.2f;
// 각속도를 호로 표현
if (Mathf.Abs(deltaAngle) > 0.1f)
{
float angle = angleStep * i;
Vector3 point = start + Quaternion.Euler(0, angle, 0) * transform.forward * radius;
arcPoints[i] = point;
Vector3[] arcPoints = new Vector3[10];
float radius = debugLineLength * 1.05f;
float angleStep = deltaAngle * 1f / (arcPoints.Length - 1);
for (int i = 0; i < arcPoints.Length; i++)
{
float angle = angleStep * i;
Vector3 point = start + Quaternion.Euler(0, angle, 0) * transform.forward * radius;
arcPoints[i] = point;
}
_rotationDeltaLineRenderer.positionCount = arcPoints.Length;
_rotationDeltaLineRenderer.SetPositions(arcPoints);
}
else
{
_rotationDeltaLineRenderer.positionCount = 0;
}
}
private void UpdateTiltLine()
{
Vector3 start = transform.position + Vector3.up * 1.5f;
Vector3 tiltDirection = meshTransform.up;
DrawLine(_TiltLineRenderer, start, start + tiltDirection * debugLineLength * 0.4f);
}
private void UpdateWaveVisualization()
{
// 현재 파도 높이 표시
Vector3 waveStart = transform.position + Vector3.up * 1.5f - transform.forward * 1.5f;
Vector3 waveEnd = waveStart + Vector3.up * currentWaveHeight * debugLineLength;
DrawLine(_waveHeightLineRenderer, waveStart, waveEnd);
// 파도 패턴 시각화
Vector3[] wavePoints = new Vector3[_wavePatternLineRenderer.positionCount];
float waveLength = debugLineLength * 2f;
for (int i = 0; i < wavePoints.Length; i++)
{
float t = (float)i / (_wavePatternLineRenderer.positionCount - 1);
float x = t * waveLength - waveLength * 0.5f;
float currentSpeedByUnit = currentSpeed / waveUnitSpeed;
currentSpeedByUnit = Mathf.Clamp01(currentSpeedByUnit);
float waveHeight = Mathf.Lerp(minSpeedWaveHeight, maxSpeedWaveHeight, currentSpeedByUnit);
float y = Mathf.Sin((waveTime + x) * baseWaveFrequency) * waveHeight;
wavePoints[i] = transform.position +
Vector3.right * x +
Vector3.up * (y + 2f); // 높이 오프셋
wavePoints[i] += Vector3.back * 3f + Vector3.down * 1f;
}
_rotationDeltaLineRenderer.positionCount = arcPoints.Length;
_rotationDeltaLineRenderer.SetPositions(arcPoints);
_wavePatternLineRenderer.SetPositions(wavePoints);
}
else
private LineRenderer CreateLineRenderer(string name, Color color)
{
_rotationDeltaLineRenderer.positionCount = 0;
GameObject lineObj = new GameObject(name);
lineObj.transform.SetParent(transform);
LineRenderer line = lineObj.AddComponent<LineRenderer>();
line.startWidth = debugLineWidth;
line.endWidth = debugLineWidth;
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 UpdateTiltLine()
{
Vector3 start = transform.position + Vector3.up * 1.5f;
Vector3 tiltDirection = _meshTransform.up;
DrawLine(_TiltLineRenderer, start, start + tiltDirection * debugLineLength * 0.4f);
}
private void UpdateWaveVisualization()
{
// 현재 파도 높이 표시
Vector3 waveStart = transform.position + Vector3.up*1.5f - transform.forward*1.5f;
Vector3 waveEnd = waveStart + Vector3.up * _currentWaveHeight * debugLineLength;
DrawLine(_waveHeightLineRenderer, waveStart, waveEnd);
// 파도 패턴 시각화
Vector3[] wavePoints = new Vector3[_wavePatternLineRenderer.positionCount];
float waveLength = debugLineLength * 2f;
for (int i = 0; i < wavePoints.Length; i++)
private void DrawLine(LineRenderer line, Vector3 start, Vector3 end)
{
float t = (float)i / (_wavePatternLineRenderer.positionCount - 1);
float x = t * waveLength - waveLength * 0.5f;
float currentSpeedByUnit = _currentSpeed / waveUnitSpeed;
currentSpeedByUnit = Mathf.Clamp01(currentSpeedByUnit);
float waveHeight = Mathf.Lerp(minSpeedWaveHeight, maxSpeedWaveHeight, currentSpeedByUnit);
float y = Mathf.Sin((_waveTime + x) * baseWaveFrequency) * waveHeight;
wavePoints[i] = transform.position +
Vector3.right * x +
Vector3.up * (y + 2f); // 높이 오프셋
wavePoints[i] += Vector3.back * 3f + Vector3.down * 1f;
if (line is null) return;
line.positionCount = 2;
line.SetPosition(0, start);
line.SetPosition(1, end);
}
_wavePatternLineRenderer.SetPositions(wavePoints);
}
private LineRenderer CreateLineRenderer(string name, Color color)
{
GameObject lineObj = new GameObject(name);
lineObj.transform.SetParent(transform);
LineRenderer line = lineObj.AddComponent<LineRenderer>();
line.startWidth = debugLineWidth;
line.endWidth = debugLineWidth;
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 DrawLine(LineRenderer line, Vector3 start, Vector3 end)
{
if (line == null) return;
line.positionCount = 2;
line.SetPosition(0, start);
line.SetPosition(1, end);
}
#endif
}