void UCrowdFollowingComponent::FollowPathSegment(float DeltaTime) { if (!bEnableCrowdSimulation) { Super::FollowPathSegment(DeltaTime); return; } if (bUpdateDirectMoveVelocity) { const FVector CurrentTargetPt = DestinationActor.IsValid() ? DestinationActor->GetActorLocation() : GetCurrentTargetLocation(); const FVector AgentLoc = GetCrowdAgentLocation(); const FVector NewDirection = (CurrentTargetPt - AgentLoc).GetSafeNormal(); const bool bDirectionChanged = !NewDirection.Equals(CrowdAgentMoveDirection); if (bDirectionChanged) { CurrentDestination.Set(Path->GetBaseActor(), CurrentTargetPt); CrowdAgentMoveDirection = NewDirection; MoveSegmentDirection = NewDirection; UCrowdManager* Manager = UCrowdManager::GetCurrent(GetWorld()); Manager->SetAgentMoveDirection(this, NewDirection); UE_VLOG(GetOwner(), LogCrowdFollowing, Log, TEXT("Updated direct move direction for crowd agent.")); } } UpdateMoveFocus(); }
void UCrowdFollowingComponent::FollowPathSegment(float DeltaTime) { if (!bEnableCrowdSimulation) { Super::FollowPathSegment(DeltaTime); return; } if (bUpdateDirectMoveVelocity && DestinationActor.IsValid()) { const FVector CurrentTargetPt = DestinationActor->GetActorLocation(); const float DistSq = (CurrentTargetPt - GetCurrentTargetLocation()).SizeSquared(); if (DistSq > FMath::Square(10.0f)) { UCrowdManager* Manager = UCrowdManager::GetCurrent(GetWorld()); const FVector AgentLoc = GetCrowdAgentLocation(); CurrentDestination.Set(Path->GetBaseActor(), CurrentTargetPt); CrowdAgentMoveDirection = (CurrentTargetPt - AgentLoc).GetSafeNormal(); MoveSegmentDirection = CrowdAgentMoveDirection; Manager->SetAgentMoveDirection(this, MoveSegmentDirection); UE_VLOG(GetOwner(), LogCrowdFollowing, Log, TEXT("Updated direct move direction for crowd agent.")); } } UpdateMoveFocus(); }
void UCrowdFollowingComponent::SetMoveSegment(int32 SegmentStartIndex) { if (!bEnableCrowdSimulation) { Super::SetMoveSegment(SegmentStartIndex); return; } PathStartIndex = SegmentStartIndex; LastPathPolyIndex = PathStartIndex; if (Path.IsValid() == false || Path->IsValid() == false || GetOwner() == NULL) { return; } FVector CurrentTargetPt = Path->GetPathPoints()[1].Location; FNavMeshPath* NavMeshPath = Path->CastPath<FNavMeshPath>(); FAbstractNavigationPath* DirectPath = Path->CastPath<FAbstractNavigationPath>(); if (NavMeshPath) { #if WITH_RECAST if (NavMeshPath->PathCorridor.IsValidIndex(PathStartIndex) == false) { // this should never matter, but just in case UE_VLOG(GetOwner(), LogCrowdFollowing, Error, TEXT("SegmentStartIndex in call to UCrowdFollowingComponent::SetMoveSegment is out of path corridor array's bounds (index: %d, array size %d)") , PathStartIndex, NavMeshPath->PathCorridor.Num()); PathStartIndex = FMath::Clamp<int32>(PathStartIndex, 0, NavMeshPath->PathCorridor.Num() - 1); } // cut paths into parts to avoid problems with crowds getting into local minimum // due to using only first 10 steps of A* // do NOT use PathPoints here, crowd simulation disables path post processing // which means, that PathPoints contains only start and end position // full path is available through PathCorridor array (poly refs) ARecastNavMesh* RecastNavData = Cast<ARecastNavMesh>(MyNavData); const int32 PathPartSize = 15; const int32 LastPolyIdx = NavMeshPath->PathCorridor.Num() - 1; int32 PathPartEndIdx = FMath::Min(PathStartIndex + PathPartSize, LastPolyIdx); FVector PtA, PtB; const bool bStartIsNavLink = RecastNavData->GetLinkEndPoints(NavMeshPath->PathCorridor[PathStartIndex], PtA, PtB); const bool bEndIsNavLink = RecastNavData->GetLinkEndPoints(NavMeshPath->PathCorridor[PathPartEndIdx], PtA, PtB); if (bStartIsNavLink) { PathStartIndex = FMath::Max(0, PathStartIndex - 1); } if (bEndIsNavLink) { PathPartEndIdx = FMath::Max(0, PathPartEndIdx - 1); } bFinalPathPart = (PathPartEndIdx == LastPolyIdx); if (!bFinalPathPart) { RecastNavData->GetPolyCenter(NavMeshPath->PathCorridor[PathPartEndIdx], CurrentTargetPt); } else if (NavMeshPath->IsPartial()) { RecastNavData->GetClosestPointOnPoly(NavMeshPath->PathCorridor[PathPartEndIdx], Path->GetPathPoints()[1].Location, CurrentTargetPt); } // not safe to read those directions yet, you have to wait until crowd manager gives you next corner of string pulled path CrowdAgentMoveDirection = FVector::ZeroVector; MoveSegmentDirection = FVector::ZeroVector; CurrentDestination.Set(Path->GetBaseActor(), CurrentTargetPt); LogPathPartHelper(GetOwner(), NavMeshPath, PathStartIndex, PathPartEndIdx); UE_VLOG_SEGMENT(GetOwner(), LogCrowdFollowing, Log, MovementComp->GetActorFeetLocation(), CurrentTargetPt, FColor::Red, TEXT("path part")); UE_VLOG(GetOwner(), LogCrowdFollowing, Log, TEXT("SetMoveSegment, from:%d segments:%d%s"), PathStartIndex, (PathPartEndIdx - PathStartIndex)+1, bFinalPathPart ? TEXT(" (final)") : TEXT("")); UCrowdManager* CrowdManager = UCrowdManager::GetCurrent(GetWorld()); if (CrowdManager) { CrowdManager->SetAgentMovePath(this, NavMeshPath, PathStartIndex, PathPartEndIdx); } #endif } else if (DirectPath) { // direct paths are not using any steering or avoidance // pathfinding is replaced with simple velocity request const FVector AgentLoc = MovementComp->GetActorFeetLocation(); bFinalPathPart = true; bCheckMovementAngle = true; bUpdateDirectMoveVelocity = true; CurrentDestination.Set(Path->GetBaseActor(), CurrentTargetPt); CrowdAgentMoveDirection = (CurrentTargetPt - AgentLoc).GetSafeNormal(); MoveSegmentDirection = CrowdAgentMoveDirection; UE_VLOG(GetOwner(), LogCrowdFollowing, Log, TEXT("SetMoveSegment, direct move")); UE_VLOG_SEGMENT(GetOwner(), LogCrowdFollowing, Log, AgentLoc, CurrentTargetPt, FColor::Red, TEXT("path")); UCrowdManager* CrowdManager = UCrowdManager::GetCurrent(GetWorld()); if (CrowdManager) { CrowdManager->SetAgentMoveDirection(this, CrowdAgentMoveDirection); } } else { UE_VLOG(GetOwner(), LogCrowdFollowing, Error, TEXT("SetMoveSegment, unknown path type!")); } }