11
This commit is contained in:
@@ -9,33 +9,62 @@ public class RaftRiverController : MonoBehaviour
|
||||
[Header("Steering Input")]
|
||||
[SerializeField] private SteeringKeyXR steeringKey;
|
||||
|
||||
[Tooltip("체크하면 키 움직임과 반대로 뗏목이 좌우 이동합니다.")]
|
||||
[Tooltip("Invert left/right steering input.")]
|
||||
[SerializeField] private bool reverseControl = true;
|
||||
|
||||
[Header("Move Speed")]
|
||||
[SerializeField] private float forwardSpeed = 5f;
|
||||
[SerializeField] private float turnSpeed = 4f;
|
||||
|
||||
[Header("Start Speed Control")]
|
||||
[Tooltip("0이면 정지, 1이면 정상 속도입니다. 시작 가속용으로 사용합니다.")]
|
||||
[SerializeField] private float speedMultiplier = 1f;
|
||||
|
||||
[Header("Side Control")]
|
||||
[SerializeField] private float sideMoveSpeed = 16f;
|
||||
[SerializeField] private float sideAcceleration = 40f;
|
||||
|
||||
[Tooltip("강 중앙선 기준 좌우 이동 가능 범위입니다. 동굴 폭 46이면 14~16 추천.")]
|
||||
[Tooltip("Maximum side movement from the raft center line.")]
|
||||
[SerializeField] private float maxSideOffset = 16f;
|
||||
|
||||
[Header("Path Follow Feel")]
|
||||
[SerializeField] private float pathFollowSmoothTime = 0.28f;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float rotationVelocityBlend = 0.45f;
|
||||
|
||||
[SerializeField] private float steeringYawAngle = 18f;
|
||||
|
||||
[Header("Manual Steering")]
|
||||
[Tooltip("Degrees per second SteeringKeyXR can turn the raft travel direction while held.")]
|
||||
[SerializeField] private float grabbedSteeringTurnSpeed = 75f;
|
||||
|
||||
[Header("Arrival")]
|
||||
[SerializeField] private float pointReachDistance = 1.5f;
|
||||
[SerializeField] private float arrivalSlowDownDistance = 12f;
|
||||
[SerializeField] private float arrivalMinSpeed = 0.8f;
|
||||
|
||||
[Header("Final Stop Guard")]
|
||||
[Tooltip("마지막 포인트에 가까워지면 거리 판정으로 도착 처리합니다.")]
|
||||
[SerializeField] private float finalPointReachDistance = 3.0f;
|
||||
|
||||
[Tooltip("마지막 포인트 근처 몇 미터 안에서 지나침 감지를 할지 설정합니다.")]
|
||||
[SerializeField] private float finalStopGuardDistance = 20f;
|
||||
|
||||
[Tooltip("목표점과의 X/Z 차이가 이 값 이상 다시 커지면 지나친 것으로 판단합니다.")]
|
||||
[SerializeField] private float finalStopGuardAxisEpsilon = 0.05f;
|
||||
|
||||
[Tooltip("마지막 구간 방향 기준, 마지막 포인트를 넘어가면 즉시 도착 처리합니다.")]
|
||||
[SerializeField] private bool stopWhenPassedFinalPlane = true;
|
||||
|
||||
[Tooltip("도착 처리 시 마지막 포인트 위치로 뗏목을 스냅할지 여부입니다.")]
|
||||
[SerializeField] private bool snapToFinalPointOnArrive = true;
|
||||
|
||||
[Header("Events")]
|
||||
public UnityEvent onArrived;
|
||||
|
||||
private int currentPointIndex = 0;
|
||||
|
||||
private float sideOffset = 0f;
|
||||
private float sideVelocity = 0f;
|
||||
private float currentSteeringInput = 0f;
|
||||
@@ -45,6 +74,10 @@ public class RaftRiverController : MonoBehaviour
|
||||
private Vector3 currentRight;
|
||||
private Vector3 positionSmoothVelocity;
|
||||
private Vector3 previousPosition;
|
||||
private Vector3 startCenterPosition;
|
||||
|
||||
private Vector3 previousFinalDelta;
|
||||
private bool hasPreviousFinalDelta;
|
||||
|
||||
private bool isFinished = false;
|
||||
private bool warnedMissingSteeringKey;
|
||||
@@ -62,19 +95,28 @@ private void Start()
|
||||
|
||||
if (pathPoints == null || pathPoints.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[RaftRiverController] Path Points가 비어 있습니다.", this);
|
||||
Debug.LogWarning("[RaftRiverController] Path Points are empty.", this);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
currentCenterPosition = transform.position;
|
||||
currentForward = transform.forward;
|
||||
currentRight = transform.right;
|
||||
previousPosition = transform.position;
|
||||
startCenterPosition = currentCenterPosition;
|
||||
|
||||
// 첫 목표 지점은 0번이 아니라 1번부터 가는 것이 자연스러울 때가 많음.
|
||||
// 단, 0번이 현재 위치와 다르면 그대로 0번부터 이동.
|
||||
currentForward = transform.forward;
|
||||
currentForward.y = 0f;
|
||||
|
||||
if (currentForward.sqrMagnitude < 0.001f)
|
||||
currentForward = Vector3.forward;
|
||||
|
||||
currentForward.Normalize();
|
||||
|
||||
currentRight = Vector3.Cross(Vector3.up, currentForward).normalized;
|
||||
|
||||
previousPosition = transform.position;
|
||||
currentPointIndex = 0;
|
||||
|
||||
ResetFinalStopGuard();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
@@ -82,56 +124,95 @@ private void Update()
|
||||
if (isFinished)
|
||||
return;
|
||||
|
||||
MoveAlongPath();
|
||||
HandleSideControl();
|
||||
|
||||
bool arrived = MoveAlongPath();
|
||||
|
||||
if (arrived)
|
||||
return;
|
||||
|
||||
ApplyRaftPositionAndRotation();
|
||||
}
|
||||
|
||||
private void MoveAlongPath()
|
||||
private bool MoveAlongPath()
|
||||
{
|
||||
SkipMissingPathPoints();
|
||||
|
||||
if (currentPointIndex >= pathPoints.Length)
|
||||
int lastPointIndex = GetLastValidPathPointIndex();
|
||||
|
||||
if (lastPointIndex < 0 || currentPointIndex >= pathPoints.Length)
|
||||
{
|
||||
FinishRaftRide();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
Transform targetPoint = pathPoints[currentPointIndex];
|
||||
|
||||
Vector3 toTarget = targetPoint.position - currentCenterPosition;
|
||||
toTarget.y = 0f;
|
||||
if (targetPoint == null)
|
||||
return false;
|
||||
|
||||
Vector3 toTarget = GetFlatVectorTo(targetPoint.position);
|
||||
float distance = toTarget.magnitude;
|
||||
|
||||
if (distance < pointReachDistance)
|
||||
bool isLastTarget = currentPointIndex == lastPointIndex;
|
||||
|
||||
while (!isLastTarget && ShouldAdvancePathPoint(currentPointIndex, distance))
|
||||
{
|
||||
currentPointIndex++;
|
||||
SkipMissingPathPoints();
|
||||
|
||||
if (currentPointIndex >= pathPoints.Length)
|
||||
{
|
||||
FinishRaftRide();
|
||||
return;
|
||||
FinishAtFinalPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
targetPoint = pathPoints[currentPointIndex];
|
||||
toTarget = targetPoint.position - currentCenterPosition;
|
||||
toTarget.y = 0f;
|
||||
|
||||
if (targetPoint == null)
|
||||
return false;
|
||||
|
||||
toTarget = GetFlatVectorTo(targetPoint.position);
|
||||
distance = toTarget.magnitude;
|
||||
isLastTarget = currentPointIndex == lastPointIndex;
|
||||
}
|
||||
|
||||
if (isLastTarget && IsCloseEnoughToFinalPoint(distance))
|
||||
{
|
||||
FinishAtFinalPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (toTarget.sqrMagnitude < 0.001f)
|
||||
return;
|
||||
return false;
|
||||
|
||||
currentForward = toTarget.normalized;
|
||||
currentCenterPosition += currentForward * forwardSpeed * Time.deltaTime;
|
||||
Vector3 pathForward = toTarget.normalized;
|
||||
currentForward = GetTravelForward(pathForward);
|
||||
|
||||
// 진행 방향 기준 오른쪽 벡터
|
||||
currentRight = Vector3.Cross(Vector3.up, currentForward).normalized;
|
||||
float currentSpeed = GetCurrentForwardSpeed(distance);
|
||||
float moveDistance = currentSpeed * Time.deltaTime;
|
||||
|
||||
if (isLastTarget && moveDistance >= distance)
|
||||
{
|
||||
FinishAtFinalPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
currentCenterPosition += currentForward * moveDistance;
|
||||
|
||||
if (currentForward.sqrMagnitude > 0.001f)
|
||||
currentRight = Vector3.Cross(Vector3.up, currentForward).normalized;
|
||||
|
||||
if (TryFinishAtFinalPointByGuards())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void HandleSideControl()
|
||||
{
|
||||
float input = 0f;
|
||||
|
||||
ResolveSteeringKey();
|
||||
|
||||
if (steeringKey != null)
|
||||
@@ -145,19 +226,17 @@ private void HandleSideControl()
|
||||
if (!warnedMissingSteeringKey)
|
||||
{
|
||||
warnedMissingSteeringKey = true;
|
||||
Debug.LogWarning("[RaftRiverController] SteeringKeyXR 참조가 없어 좌우 조향 없이 전진합니다.", this);
|
||||
Debug.LogWarning("[RaftRiverController] SteeringKeyXR reference is missing. Falling back to legacy horizontal input.", this);
|
||||
}
|
||||
}
|
||||
|
||||
// 반전은 여기서만 처리
|
||||
if (reverseControl)
|
||||
{
|
||||
input *= -1f;
|
||||
}
|
||||
|
||||
currentSteeringInput = input;
|
||||
|
||||
float targetSideVelocity = input * sideMoveSpeed;
|
||||
|
||||
sideVelocity = Mathf.MoveTowards(
|
||||
sideVelocity,
|
||||
targetSideVelocity,
|
||||
@@ -179,11 +258,10 @@ private void ApplyRaftPositionAndRotation()
|
||||
previousPosition = transform.position;
|
||||
|
||||
Vector3 targetPosition = currentCenterPosition + currentRight * sideOffset;
|
||||
|
||||
// 현재 뗏목 높이 유지
|
||||
targetPosition.y = transform.position.y;
|
||||
|
||||
float smoothTime = Mathf.Max(0.01f, pathFollowSmoothTime);
|
||||
|
||||
transform.position = Vector3.SmoothDamp(
|
||||
transform.position,
|
||||
targetPosition,
|
||||
@@ -197,6 +275,7 @@ private void ApplyRaftPositionAndRotation()
|
||||
frameVelocity.y = 0f;
|
||||
|
||||
Vector3 lookDirection = currentForward;
|
||||
|
||||
if (frameVelocity.sqrMagnitude > 0.0001f)
|
||||
{
|
||||
lookDirection = Vector3.Slerp(
|
||||
@@ -206,6 +285,9 @@ private void ApplyRaftPositionAndRotation()
|
||||
);
|
||||
}
|
||||
|
||||
if (lookDirection.sqrMagnitude < 0.001f)
|
||||
return;
|
||||
|
||||
Quaternion targetRotation =
|
||||
Quaternion.LookRotation(lookDirection, Vector3.up) *
|
||||
Quaternion.Euler(0f, currentSteeringInput * steeringYawAngle, 0f);
|
||||
@@ -218,14 +300,158 @@ private void ApplyRaftPositionAndRotation()
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsCloseEnoughToFinalPoint(float distance)
|
||||
{
|
||||
float reachDistance = Mathf.Max(pointReachDistance, finalPointReachDistance);
|
||||
return distance <= reachDistance;
|
||||
}
|
||||
|
||||
private bool TryFinishAtFinalPointByGuards()
|
||||
{
|
||||
int lastPointIndex = GetLastValidPathPointIndex();
|
||||
|
||||
if (lastPointIndex < 0)
|
||||
return false;
|
||||
|
||||
if (currentPointIndex != lastPointIndex)
|
||||
{
|
||||
ResetFinalStopGuard();
|
||||
return false;
|
||||
}
|
||||
|
||||
Transform finalPoint = pathPoints[lastPointIndex];
|
||||
|
||||
if (finalPoint == null)
|
||||
return false;
|
||||
|
||||
Vector3 finalDelta = finalPoint.position - currentCenterPosition;
|
||||
finalDelta.y = 0f;
|
||||
|
||||
float distanceToFinal = finalDelta.magnitude;
|
||||
|
||||
if (distanceToFinal <= finalPointReachDistance)
|
||||
{
|
||||
Debug.Log("[RaftRiverController] Final point reach distance 안에 들어와 도착 처리합니다.");
|
||||
FinishAtFinalPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (stopWhenPassedFinalPlane && HasPassedFinalPlane())
|
||||
{
|
||||
Debug.Log("[RaftRiverController] 마지막 도착 평면을 지나 도착 처리합니다.");
|
||||
FinishAtFinalPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryFinishIfMovingAwayFromFinalPoint(finalDelta, distanceToFinal))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool HasPassedFinalPlane()
|
||||
{
|
||||
int lastPointIndex = GetLastValidPathPointIndex();
|
||||
int penultimateIndex = GetPenultimateValidPathPointIndex();
|
||||
|
||||
if (lastPointIndex < 0 || penultimateIndex < 0 || lastPointIndex == penultimateIndex)
|
||||
return false;
|
||||
|
||||
Transform finalPoint = pathPoints[lastPointIndex];
|
||||
Transform previousPoint = pathPoints[penultimateIndex];
|
||||
|
||||
if (finalPoint == null || previousPoint == null)
|
||||
return false;
|
||||
|
||||
Vector3 previousPos = previousPoint.position;
|
||||
Vector3 finalPos = finalPoint.position;
|
||||
Vector3 centerPos = currentCenterPosition;
|
||||
|
||||
previousPos.y = 0f;
|
||||
finalPos.y = 0f;
|
||||
centerPos.y = 0f;
|
||||
|
||||
Vector3 finalSegmentDirection = finalPos - previousPos;
|
||||
|
||||
if (finalSegmentDirection.sqrMagnitude < 0.001f)
|
||||
return false;
|
||||
|
||||
finalSegmentDirection.Normalize();
|
||||
|
||||
Vector3 fromFinalToRaft = centerPos - finalPos;
|
||||
|
||||
float passedAmount = Vector3.Dot(fromFinalToRaft, finalSegmentDirection);
|
||||
|
||||
return passedAmount >= 0f;
|
||||
}
|
||||
|
||||
private bool TryFinishIfMovingAwayFromFinalPoint(Vector3 finalDelta, float distanceToFinal)
|
||||
{
|
||||
if (distanceToFinal > finalStopGuardDistance)
|
||||
{
|
||||
previousFinalDelta = finalDelta;
|
||||
hasPreviousFinalDelta = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasPreviousFinalDelta)
|
||||
{
|
||||
previousFinalDelta = finalDelta;
|
||||
hasPreviousFinalDelta = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 previousAbs = new Vector3(
|
||||
Mathf.Abs(previousFinalDelta.x),
|
||||
0f,
|
||||
Mathf.Abs(previousFinalDelta.z)
|
||||
);
|
||||
|
||||
Vector3 currentAbs = new Vector3(
|
||||
Mathf.Abs(finalDelta.x),
|
||||
0f,
|
||||
Mathf.Abs(finalDelta.z)
|
||||
);
|
||||
|
||||
bool xMovingAway = currentAbs.x > previousAbs.x + finalStopGuardAxisEpsilon;
|
||||
bool zMovingAway = currentAbs.z > previousAbs.z + finalStopGuardAxisEpsilon;
|
||||
|
||||
if (xMovingAway || zMovingAway)
|
||||
{
|
||||
Debug.Log("[RaftRiverController] 마지막 포인트에서 멀어지는 것으로 판단하여 도착 처리합니다.");
|
||||
FinishAtFinalPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
previousFinalDelta = finalDelta;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void FinishAtFinalPoint()
|
||||
{
|
||||
int lastPointIndex = GetLastValidPathPointIndex();
|
||||
|
||||
if (lastPointIndex >= 0 && pathPoints[lastPointIndex] != null && snapToFinalPointOnArrive)
|
||||
{
|
||||
SnapToPathPoint(pathPoints[lastPointIndex]);
|
||||
}
|
||||
|
||||
FinishRaftRide();
|
||||
}
|
||||
|
||||
private void FinishRaftRide()
|
||||
{
|
||||
if (isFinished)
|
||||
return;
|
||||
|
||||
isFinished = true;
|
||||
SetSpeedMultiplier(0f);
|
||||
|
||||
Debug.Log("[RaftRiverController] 목적지 도착. 뗏목 정지.");
|
||||
sideVelocity = 0f;
|
||||
currentSteeringInput = 0f;
|
||||
positionSmoothVelocity = Vector3.zero;
|
||||
|
||||
Debug.Log("[RaftRiverController] Arrived at destination. Raft stopped.");
|
||||
|
||||
onArrived?.Invoke();
|
||||
}
|
||||
@@ -233,11 +459,20 @@ private void FinishRaftRide()
|
||||
public void StopRaft()
|
||||
{
|
||||
isFinished = true;
|
||||
sideVelocity = 0f;
|
||||
currentSteeringInput = 0f;
|
||||
positionSmoothVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
public void ResumeRaft()
|
||||
{
|
||||
isFinished = false;
|
||||
ResetFinalStopGuard();
|
||||
}
|
||||
|
||||
public void SetSpeedMultiplier(float value)
|
||||
{
|
||||
speedMultiplier = Mathf.Clamp01(value);
|
||||
}
|
||||
|
||||
public void SetSteeringKey(SteeringKeyXR newSteeringKey)
|
||||
@@ -254,6 +489,216 @@ private void ResolveSteeringKey()
|
||||
steeringKey = GetComponentInChildren<SteeringKeyXR>(true);
|
||||
}
|
||||
|
||||
private Vector3 GetTravelForward(Vector3 fallbackForward)
|
||||
{
|
||||
Vector3 travelForward = currentForward;
|
||||
travelForward.y = 0f;
|
||||
|
||||
if (travelForward.sqrMagnitude < 0.001f)
|
||||
travelForward = transform.forward;
|
||||
|
||||
travelForward.y = 0f;
|
||||
|
||||
if (travelForward.sqrMagnitude < 0.001f)
|
||||
travelForward = fallbackForward;
|
||||
|
||||
if (steeringKey != null && steeringKey.IsGrabbed)
|
||||
{
|
||||
float turnAmount =
|
||||
currentSteeringInput *
|
||||
Mathf.Max(0f, grabbedSteeringTurnSpeed) *
|
||||
Time.deltaTime;
|
||||
|
||||
travelForward = Quaternion.Euler(0f, turnAmount, 0f) * travelForward.normalized;
|
||||
}
|
||||
|
||||
return travelForward.normalized;
|
||||
}
|
||||
|
||||
private Vector3 GetFlatVectorTo(Vector3 worldPosition)
|
||||
{
|
||||
Vector3 delta = worldPosition - currentCenterPosition;
|
||||
delta.y = 0f;
|
||||
return delta;
|
||||
}
|
||||
|
||||
private bool ShouldAdvancePathPoint(int targetIndex, float distanceToTarget)
|
||||
{
|
||||
return distanceToTarget < pointReachDistance || HasPassedPathPoint(targetIndex);
|
||||
}
|
||||
|
||||
private bool HasPassedPathPoint(int targetIndex)
|
||||
{
|
||||
if (pathPoints == null ||
|
||||
targetIndex < 0 ||
|
||||
targetIndex >= pathPoints.Length ||
|
||||
pathPoints[targetIndex] == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector3 anchorPosition = GetPreviousPathAnchorPosition(targetIndex);
|
||||
Vector3 targetPosition = pathPoints[targetIndex].position;
|
||||
|
||||
anchorPosition.y = currentCenterPosition.y;
|
||||
targetPosition.y = currentCenterPosition.y;
|
||||
|
||||
Vector3 segment = targetPosition - anchorPosition;
|
||||
|
||||
if (segment.sqrMagnitude < 0.001f)
|
||||
return false;
|
||||
|
||||
Vector3 fromAnchor = currentCenterPosition - anchorPosition;
|
||||
fromAnchor.y = 0f;
|
||||
|
||||
return Vector3.Dot(fromAnchor, segment.normalized) >= segment.magnitude;
|
||||
}
|
||||
|
||||
private Vector3 GetPreviousPathAnchorPosition(int targetIndex)
|
||||
{
|
||||
if (pathPoints != null)
|
||||
{
|
||||
for (int i = targetIndex - 1; i >= 0; i--)
|
||||
{
|
||||
if (pathPoints[i] != null)
|
||||
return pathPoints[i].position;
|
||||
}
|
||||
}
|
||||
|
||||
return startCenterPosition;
|
||||
}
|
||||
|
||||
private void SnapToPathPoint(Transform point)
|
||||
{
|
||||
if (point == null)
|
||||
return;
|
||||
|
||||
Vector3 finalPosition = point.position;
|
||||
finalPosition.y = transform.position.y;
|
||||
|
||||
currentCenterPosition = finalPosition;
|
||||
|
||||
sideOffset = 0f;
|
||||
sideVelocity = 0f;
|
||||
currentSteeringInput = 0f;
|
||||
positionSmoothVelocity = Vector3.zero;
|
||||
previousPosition = finalPosition;
|
||||
|
||||
transform.position = finalPosition;
|
||||
|
||||
ResetFinalStopGuard();
|
||||
}
|
||||
|
||||
private int GetPenultimateValidPathPointIndex()
|
||||
{
|
||||
if (pathPoints == null)
|
||||
return -1;
|
||||
|
||||
int lastValidIndex = -1;
|
||||
|
||||
for (int i = pathPoints.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (pathPoints[i] == null)
|
||||
continue;
|
||||
|
||||
if (lastValidIndex < 0)
|
||||
{
|
||||
lastValidIndex = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return lastValidIndex;
|
||||
}
|
||||
|
||||
private float GetArrivalSlowDownDistance()
|
||||
{
|
||||
float fallbackDistance = Mathf.Max(pointReachDistance + 0.01f, arrivalSlowDownDistance);
|
||||
|
||||
int penultimateIndex = GetPenultimateValidPathPointIndex();
|
||||
int lastPointIndex = GetLastValidPathPointIndex();
|
||||
|
||||
if (penultimateIndex < 0 ||
|
||||
lastPointIndex < 0 ||
|
||||
penultimateIndex == lastPointIndex)
|
||||
{
|
||||
return fallbackDistance;
|
||||
}
|
||||
|
||||
Vector3 penultimatePosition = pathPoints[penultimateIndex].position;
|
||||
Vector3 finalPosition = pathPoints[lastPointIndex].position;
|
||||
|
||||
penultimatePosition.y = 0f;
|
||||
finalPosition.y = 0f;
|
||||
|
||||
float finalSegmentDistance = Vector3.Distance(penultimatePosition, finalPosition);
|
||||
|
||||
if (finalSegmentDistance <= pointReachDistance)
|
||||
return fallbackDistance;
|
||||
|
||||
return Mathf.Max(pointReachDistance + 0.01f, finalSegmentDistance);
|
||||
}
|
||||
|
||||
private float GetCurrentForwardSpeed(float distanceToTarget)
|
||||
{
|
||||
float baseSpeed;
|
||||
|
||||
if (currentPointIndex != GetLastValidPathPointIndex())
|
||||
{
|
||||
baseSpeed = forwardSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
float maxSpeed = Mathf.Max(0f, forwardSpeed);
|
||||
|
||||
if (maxSpeed <= 0.01f)
|
||||
{
|
||||
baseSpeed = maxSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
float slowDownDistance = GetArrivalSlowDownDistance();
|
||||
|
||||
if (slowDownDistance <= pointReachDistance)
|
||||
{
|
||||
baseSpeed = maxSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
float minSpeed = Mathf.Clamp(arrivalMinSpeed, 0.01f, maxSpeed);
|
||||
|
||||
float speedRatio = Mathf.InverseLerp(
|
||||
pointReachDistance,
|
||||
slowDownDistance,
|
||||
distanceToTarget
|
||||
);
|
||||
|
||||
speedRatio = speedRatio * speedRatio * (3f - 2f * speedRatio);
|
||||
|
||||
baseSpeed = Mathf.Lerp(minSpeed, maxSpeed, speedRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return baseSpeed * speedMultiplier;
|
||||
}
|
||||
|
||||
private int GetLastValidPathPointIndex()
|
||||
{
|
||||
if (pathPoints == null)
|
||||
return -1;
|
||||
|
||||
for (int i = pathPoints.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (pathPoints[i] != null)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void SkipMissingPathPoints()
|
||||
{
|
||||
while (currentPointIndex < pathPoints.Length && pathPoints[currentPointIndex] == null)
|
||||
@@ -262,6 +707,12 @@ private void SkipMissingPathPoints()
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetFinalStopGuard()
|
||||
{
|
||||
previousFinalDelta = Vector3.zero;
|
||||
hasPreviousFinalDelta = false;
|
||||
}
|
||||
|
||||
private float ReadLegacyHorizontalInput()
|
||||
{
|
||||
#if ENABLE_LEGACY_INPUT_MANAGER
|
||||
@@ -270,4 +721,4 @@ private float ReadLegacyHorizontalInput()
|
||||
return 0f;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user