DDD-43 이동 기본 구현
This commit is contained in:
parent
0d2a8a5e2c
commit
70702f3235
@ -105,6 +105,18 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 2607481b15fd548b18ca4897db56ab3f, type: 3}
|
m_Script: {fileID: 11500000, guid: 2607481b15fd548b18ca4897db56ab3f, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
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
|
--- !u!1 &6407855916708530114
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -118,7 +130,7 @@ GameObject:
|
|||||||
- component: {fileID: 9176830315433650152}
|
- component: {fileID: 9176830315433650152}
|
||||||
- component: {fileID: 8182957266188503550}
|
- component: {fileID: 8182957266188503550}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Sphere
|
m_Name: Ship_Mesh
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
@ -134,8 +146,8 @@ Transform:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 2, y: 2, z: 2}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 7177504742663284911}
|
m_Father: {fileID: 7177504742663284911}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
@ -3,66 +3,249 @@ using UnityEngine.InputSystem;
|
|||||||
|
|
||||||
public class VoyagePlayerShipMovement : MonoBehaviour
|
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
|
#if UNITY_EDITOR
|
||||||
// 현재 방향을 표시할 LineRenderer 설정
|
[Header("Debug Settings")]
|
||||||
forwardDirectionLine = CreateLineRenderer("CurrentDirectionLine", Color.green);
|
[SerializeField] private bool showDebugLines = true;
|
||||||
upDirectionLine = CreateLineRenderer("upDirectionLine", Color.yellow);
|
|
||||||
// 입력 방향을 표시할 LineRenderer 설정
|
[SerializeField] private float debugLineLength = 4f;
|
||||||
inputDirectionLine = CreateLineRenderer("InputDirectionLine", Color.red);
|
[SerializeField] private float debugLineHeightStep = 0.1f;
|
||||||
#endif
|
private LineRenderer velocityLine;
|
||||||
}
|
|
||||||
|
|
||||||
public void OnMove(InputAction.CallbackContext context)
|
|
||||||
{
|
|
||||||
Vector2 inputVector = context.ReadValue<Vector2>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
private LineRenderer forwardDirectionLine;
|
private LineRenderer forwardDirectionLine;
|
||||||
private LineRenderer upDirectionLine;
|
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<Vector2>();
|
||||||
|
// 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)
|
private LineRenderer CreateLineRenderer(string name, Color color)
|
||||||
{
|
{
|
||||||
GameObject lineObj = new GameObject(name);
|
GameObject lineObj = new GameObject(name);
|
||||||
lineObj.transform.SetParent(transform);
|
lineObj.transform.SetParent(transform);
|
||||||
LineRenderer line = lineObj.AddComponent<LineRenderer>();
|
LineRenderer line = lineObj.AddComponent<LineRenderer>();
|
||||||
|
|
||||||
// LineRenderer 기본 설정
|
|
||||||
line.startWidth = 0.1f;
|
line.startWidth = 0.1f;
|
||||||
line.endWidth = 0.1f;
|
line.endWidth = 0.1f;
|
||||||
line.material = new Material(Shader.Find("Universal Render Pipeline/Unlit"));
|
line.material = new Material(Shader.Find("Universal Render Pipeline/Unlit"));
|
||||||
line.startColor = color;
|
line.startColor = color;
|
||||||
line.endColor = color;
|
line.endColor = color;
|
||||||
line.positionCount = 2;
|
line.positionCount = 2;
|
||||||
|
|
||||||
|
// 라인 렌더러가 다른 오브젝트를 가리지 않도록 설정
|
||||||
|
line.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||||
|
line.receiveShadows = false;
|
||||||
line.material.color = color;
|
line.material.color = color;
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
private void DrawDebugLine(LineRenderer renderer, Vector3 direction)
|
|
||||||
|
private void DrawDebugLine(LineRenderer renderer, Vector3 direction, float length, float heightOffset)
|
||||||
{
|
{
|
||||||
const float lineLength = 4;
|
if (!renderer) return;
|
||||||
Vector3 position = transform.position;
|
|
||||||
// 현재 방향 라인 업데이트 (파란색)
|
Vector3 position = transform.position + Vector3.up * heightOffset;
|
||||||
renderer.SetPosition(0, position);
|
renderer.SetPosition(0, position);
|
||||||
renderer.SetPosition(1, position + direction * lineLength);
|
renderer.SetPosition(1, position + direction * length);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
// 에디터에서 메시 오브젝트 이름이 변경될 때 자동으로 찾기
|
||||||
|
if (Application.isEditor && !Application.isPlaying)
|
||||||
|
{
|
||||||
|
meshTransform = transform.Find(meshObjectName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -33,7 +33,7 @@ Material:
|
|||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
- _BaseMap:
|
- _BaseMap:
|
||||||
m_Texture: {fileID: 2800000, guid: 9fab180d66628484a9bf08ce8bbd51c8, type: 3}
|
m_Texture: {fileID: 2800000, guid: b28a01dbcbf8f0c4c8b70e10b99d5a28, type: 3}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
- _BlendTex:
|
- _BlendTex:
|
||||||
|
Loading…
Reference in New Issue
Block a user