31 const float GoalRadius = 0.0f;
32 const float GoalHalfHeight = 0.0f;
33 if (InAcceptanceRadius == UPathFollowingComponent::DefaultAcceptanceRadius)
35 InAcceptanceRadius = MyDefaultAcceptanceRadius;
38 const float AgentRadiusMod = (ReachMode == EPathFollowingReachMode::ExactLocation) || (ReachMode == EPathFollowingReachMode::OverlapGoal) ? 0.0f : MinAgentRadiusPct;
39 return HasReachedInternal(TestPoint, GoalRadius, GoalHalfHeight, CurrentLocation, InAcceptanceRadius, AgentRadiusMod);
45 float GoalRadius = 0.0f;
46 float GoalHalfHeight = 0.0f;
47 FVector GoalOffset = FVector::ZeroVector;
48 FVector TestPoint = TestGoal.GetActorLocation();
49 if (InAcceptanceRadius == UPathFollowingComponent::DefaultAcceptanceRadius)
51 InAcceptanceRadius = MyDefaultAcceptanceRadius;
54 if (bUseNavAgentGoalLocation)
56 const INavAgentInterface* NavAgent = Cast<const INavAgentInterface>(&TestGoal);
59 const AActor* OwnerActor = GetOwner();
60 const FVector GoalMoveOffset = NavAgent->GetMoveGoalOffset(OwnerActor);
61 NavAgent->GetMoveGoalReachTest(OwnerActor, GoalMoveOffset, GoalOffset, GoalRadius, GoalHalfHeight);
62 TestPoint = FQuatRotationTranslationMatrix(TestGoal.GetActorQuat(), NavAgent->GetNavAgentLocation()).TransformPosition(GoalOffset);
64 if ((ReachMode == EPathFollowingReachMode::ExactLocation) || (ReachMode == EPathFollowingReachMode::OverlapAgent))
72 const float AgentRadiusMod = (ReachMode == EPathFollowingReachMode::ExactLocation) || (ReachMode == EPathFollowingReachMode::OverlapGoal) ? 0.0f : MinAgentRadiusPct;
73 return HasReachedInternal(TestPoint, GoalRadius, GoalHalfHeight, CurrentLocation, InAcceptanceRadius, AgentRadiusMod);
78 Tokens.Add(GetStatusDesc());
79 Flags.Add(EPathFollowingDebugTokens::Description);
81 if (Status != EPathFollowingStatus::Moving)
86 FString& StatusDesc = Tokens[0];
89 const int32 NumMoveSegments = (Path.IsValid() && Path->IsValid()) ? Path->GetPathPoints().Num() : -1;
90 const bool bIsDirect = (Path->CastPath<FAbstractNavigationPath>() != NULL);
91 const bool bIsCustomLink = CurrentCustomLinkOb.IsValid();
95 StatusDesc += FString::Printf(TEXT(
" (%d..%d/%d)%s"), MoveSegmentStartIndex + 1, MoveSegmentEndIndex + 1, NumMoveSegments,
96 bIsCustomLink ? TEXT(
" (custom NavLink)") : TEXT(
""));
100 StatusDesc += TEXT(
" (direct)");
105 StatusDesc += TEXT(
" (invalid path)");
109 float CurrentDot = 0.0f, CurrentDistance = 0.0f, CurrentHeight = 0.0f;
110 uint8 bFailedDot = 0, bFailedDistance = 0, bFailedHeight = 0;
111 DebugReachTest(CurrentDot, CurrentDistance, CurrentHeight, bFailedHeight, bFailedDistance, bFailedHeight);
113 Tokens.Add(TEXT(
"dot"));
114 Flags.Add(EPathFollowingDebugTokens::ParamName);
115 Tokens.Add(FString::Printf(TEXT(
"%.2f"), CurrentDot));
116 Flags.Add(bFailedDot ? EPathFollowingDebugTokens::FailedValue : EPathFollowingDebugTokens::PassedValue);
118 Tokens.Add(TEXT(
"dist2D"));
119 Flags.Add(EPathFollowingDebugTokens::ParamName);
120 Tokens.Add(FString::Printf(TEXT(
"%.0f"), CurrentDistance));
121 Flags.Add(bFailedDistance ? EPathFollowingDebugTokens::FailedValue : EPathFollowingDebugTokens::PassedValue);
123 Tokens.Add(TEXT(
"distZ"));
124 Flags.Add(EPathFollowingDebugTokens::ParamName);
125 Tokens.Add(FString::Printf(TEXT(
"%.0f"), CurrentHeight));
126 Flags.Add(bFailedHeight ? EPathFollowingDebugTokens::FailedValue : EPathFollowingDebugTokens::PassedValue);
132 if (Status == EPathFollowingStatus::Paused)
137 if (RequestID.IsEquivalent(GetCurrentRequestId()))
139 if ((VelocityMode == EPathFollowingVelocityMode::Reset) && MovementComp && HasMovementAuthority())
141 MovementComp->StopMovementKeepPathing();
145 PathTimeWhenPaused = Path.IsValid() ? Path->GetTimeStamp() : 0.0f;
146 Status = EPathFollowingStatus::Paused;
156 bool bCheckPath =
true;
157 if (MovementComp != NULL)
159 float AgentRadius = 0.0f, AgentHalfHeight = 0.0f;
160 MovementComp->GetOwner()->GetSimpleCollisionCylinder(AgentRadius, AgentHalfHeight);
162 const FVector CurrentLocation = (
VRMovementComp !=
nullptr ?
VRMovementComp->GetActorFeetLocation() : MovementComp->GetActorFeetLocation());
163 const float DeltaMove2DSq = (CurrentLocation - LocationWhenPaused).SizeSquared2D();
164 const float DeltaZ = FMath::Abs(CurrentLocation.Z - LocationWhenPaused.Z);
165 if (DeltaMove2DSq < FMath::Square(AgentRadius) && DeltaZ < (AgentHalfHeight * 0.5f))
176 int32 PickedPathPoint = INDEX_NONE;
178 if (ConsideredPath && ConsideredPath->IsValid())
182 if (MoveSegmentStartRef != INVALID_NAVNODEREF &&
183 MoveSegmentEndRef != INVALID_NAVNODEREF &&
184 ConsideredPath->GetNavigationDataUsed() != NULL)
187 for (int32 PathPoint = 0; PathPoint < ConsideredPath->GetPathPoints().Num() - 1; ++PathPoint)
189 if (ConsideredPath->GetPathPoints()[PathPoint].NodeRef == MoveSegmentStartRef &&
190 ConsideredPath->GetPathPoints()[PathPoint + 1].NodeRef == MoveSegmentEndRef)
192 PickedPathPoint = PathPoint;
198 if (MovementComp && PickedPathPoint == INDEX_NONE)
200 if (ConsideredPath->GetPathPoints().Num() > 2)
204 const FVector PathPt0 = *ConsideredPath->GetPathPointLocation(0);
205 const FVector PathPt1 = *ConsideredPath->GetPathPointLocation(1);
208 const float SqDistToFirstPoint = (CurrentLocation - PathPt0).SizeSquared2D();
209 const float SqDistToSecondPoint = (CurrentLocation - PathPt1).SizeSquared2D();
210 PickedPathPoint = FMath::IsNearlyEqual(SqDistToFirstPoint, SqDistToSecondPoint) ?
211 ((FMath::Abs(CurrentLocation.Z - PathPt0.Z) < FMath::Abs(CurrentLocation.Z - PathPt1.Z)) ? 0 : 1) :
212 ((SqDistToFirstPoint < SqDistToSecondPoint) ? 0 : 1);
222 return PickedPathPoint;
227 const float GameTime = GetWorld()->GetTimeSeconds();
228 if (bUseBlockDetection &&
230 GameTime > (LastSampleTime + BlockDetectionInterval) &&
231 BlockDetectionSampleCount > 0)
233 LastSampleTime = GameTime;
235 if (LocationSamples.Num() == NextSampleIdx)
237 LocationSamples.AddZeroed(1);
240 LocationSamples[NextSampleIdx] = (
VRMovementComp !=
nullptr ?
VRMovementComp->GetActorFeetLocationBased() : MovementComp->GetActorFeetLocationBased());
241 NextSampleIdx = (NextSampleIdx + 1) % BlockDetectionSampleCount;
250#if !UE_BUILD_SHIPPING
251 DEBUG_bMovingDirectlyToGoal =
false;
254 if ((Path.IsValid() ==
false) || (MovementComp ==
nullptr))
257 OnPathFinished(EPathFollowingResult::Aborted, FPathFollowingResultFlags::InvalidPath);
261 if (!Path->IsValid())
263 if (!Path->IsWaitingForRepath())
266 OnPathFinished(EPathFollowingResult::Aborted, FPathFollowingResultFlags::InvalidPath);
272 FMetaNavMeshPath* MetaNavPath = bIsUsingMetaPath ? Path->CastPath<FMetaNavMeshPath>() :
nullptr;
276 const bool bCanUpdateState = HasMovementAuthority();
277 if (bCanUpdateState && Status == EPathFollowingStatus::Moving)
279 const int32 LastSegmentEndIndex = Path->GetPathPoints().Num() - 1;
280 const bool bFollowingLastSegment = (MoveSegmentEndIndex >= LastSegmentEndIndex);
281 const bool bLastPathChunk = (MetaNavPath ==
nullptr || MetaNavPath->IsLastSection());
283 if (bCollidedWithGoal)
287 OnPathFinished(EPathFollowingResult::Success, FPathFollowingResultFlags::None);
289 else if (HasReachedDestination(CurrentLocation))
293 OnPathFinished(EPathFollowingResult::Success, FPathFollowingResultFlags::None);
295 else if (bFollowingLastSegment && bMoveToGoalOnLastSegment && bLastPathChunk)
299 if (DestinationActor.IsValid() && Path->IsPartial() ==
false)
301 const FVector AgentLocation = DestinationAgent ? DestinationAgent->GetNavAgentLocation() : DestinationActor->GetActorLocation();
303 const FVector GoalLocation = FQuatRotationTranslationMatrix(DestinationActor->GetActorQuat(), AgentLocation).TransformPosition(MoveOffset);
305 CurrentDestination.Set(NULL, GoalLocation);
314#if !UE_BUILD_SHIPPING
315 DEBUG_bMovingDirectlyToGoal =
true;
322 SetNextMoveSegment();
326 if (bCanUpdateState && Status == EPathFollowingStatus::Moving)
329 if (MetaNavPath && Status == EPathFollowingStatus::Moving)
331 MetaNavPath->ConditionalMoveToNextSection(CurrentLocation, EMetaPathUpdateReason::MoveTick);
336 if (bHasNewSample && IsBlocked())
338 if (Path->GetPathPoints().IsValidIndex(MoveSegmentEndIndex) && Path->GetPathPoints().IsValidIndex(MoveSegmentStartIndex))
346 if ((GetOwner() != NULL) && (MovementComp != NULL))
351 OnPathFinished(EPathFollowingResult::Blocked, FPathFollowingResultFlags::None);
358 if (!Path.IsValid() || MovementComp ==
nullptr)
364 const FVector CurrentTarget = GetCurrentTargetLocation();
367 bIsDecelerating =
false;
369 const bool bAccelerationBased = MovementComp->UseAccelerationForPathFollowing();
370 if (bAccelerationBased)
372 CurrentMoveInput = (CurrentTarget - CurrentLocation).GetSafeNormal();
374 if (MoveSegmentStartIndex >= DecelerationSegmentIndex)
376 const FVector PathEnd = Path->GetEndLocation();
377 const float DistToEndSq = FVector::DistSquared(CurrentLocation, PathEnd);
378 const bool bShouldDecelerate = DistToEndSq < FMath::Square(CachedBrakingDistance);
379 if (bShouldDecelerate)
381 bIsDecelerating =
true;
383 const float SpeedPct = FMath::Clamp(FMath::Sqrt(DistToEndSq) / CachedBrakingDistance, 0.0f, 1.0f);
384 CurrentMoveInput *= SpeedPct;
388 PostProcessMove.ExecuteIfBound(
this, CurrentMoveInput);
389 MovementComp->RequestPathMove(CurrentMoveInput);
393 FVector MoveVelocity = (CurrentTarget - CurrentLocation) / DeltaTime;
395 const int32 LastSegmentStartIndex = Path->GetPathPoints().Num() - 2;
396 const bool bNotFollowingLastSegment = (MoveSegmentStartIndex < LastSegmentStartIndex);
398 PostProcessMove.ExecuteIfBound(
this, MoveVelocity);
399 MovementComp->RequestDirectMove(MoveVelocity, bNotFollowingLastSegment);
405 if (MovementComp == NULL)
410 const FVector CurrentTarget = GetCurrentTargetLocation();
411 const FVector CurrentDirection = GetCurrentDirection();
415 const float SegmentDot = FVector::DotProduct(ToTarget, CurrentDirection);
416 if (SegmentDot < 0.0)
423 const float GoalRadius = 0.0f;
424 const float GoalHalfHeight = 0.0f;
426 return HasReachedInternal(CurrentTarget, GoalRadius, GoalHalfHeight, CurrentLocation, CurrentAcceptanceRadius, 0.05f);
431 if (!Path.IsValid() || MovementComp == NULL)
436 const int32 LastSegmentEndIndex = Path->GetPathPoints().Num() - 1;
437 const bool bFollowingLastSegment = (MoveSegmentEndIndex >= LastSegmentEndIndex);
439 float GoalRadius = 0.0f;
440 float GoalHalfHeight = 0.0f;
441 float RadiusThreshold = 0.0f;
442 float AgentRadiusPct = 0.05f;
445 FVector GoalLocation = GetCurrentTargetLocation();
446 RadiusThreshold = CurrentAcceptanceRadius;
448 if (bFollowingLastSegment)
450 GoalLocation = *Path->GetPathPointLocation(Path->GetPathPoints().Num() - 1);
451 AgentRadiusPct = MinAgentRadiusPct;
454 if (DestinationActor.IsValid() && !Path->IsPartial() && bMoveToGoalOnLastSegment)
456 if (DestinationAgent)
460 const AActor* OwnerActor = GetOwner();
461 DestinationAgent->GetMoveGoalReachTest(OwnerActor, MoveOffset, GoalOffset, GoalRadius, GoalHalfHeight);
462 GoalLocation = FQuatRotationTranslationMatrix(DestinationActor->GetActorQuat(), DestinationAgent->GetNavAgentLocation()).TransformPosition(GoalOffset);
466 GoalLocation = DestinationActor->GetActorLocation();
471 const FVector ToGoal = (GoalLocation - AgentLocation);
472 const FVector CurrentDirection = GetCurrentDirection();
473 CurrentDot = FVector::DotProduct(ToGoal.GetSafeNormal(), CurrentDirection);
474 bDotFailed = (CurrentDot < 0.0f) ? 1 : 0;
477 float AgentRadius = 0.0f;
478 float AgentHalfHeight = 0.0f;
479 AActor* MovingAgent = MovementComp->GetOwner();
480 MovingAgent->GetSimpleCollisionCylinder(AgentRadius, AgentHalfHeight);
482 CurrentDistance = ToGoal.Size2D();
483 const float UseRadius = FMath::Max(RadiusThreshold, GoalRadius + (AgentRadius * AgentRadiusPct));
484 bDistanceFailed = (CurrentDistance > UseRadius) ? 1 : 0;
486 CurrentHeight = FMath::Abs(ToGoal.Z);
487 const float UseHeight = GoalHalfHeight + (AgentHalfHeight * MinAgentHalfHeightPct);
488 bHeightFailed = (CurrentHeight > UseHeight) ? 1 : 0;