void UCrowdManager::PrepareAgentStep(const ICrowdAgentInterface* Agent, FCrowdAgentData& AgentData, float DeltaTime) const { dtCrowdAgent* ag = (dtCrowdAgent*)DetourCrowd->getAgent(AgentData.AgentIndex); ag->params.maxSpeed = Agent->GetCrowdAgentMaxSpeed(); FVector RcLocation = Unreal2RecastPoint(Agent->GetCrowdAgentLocation()); FVector RcVelocity = Unreal2RecastPoint(Agent->GetCrowdAgentVelocity()); dtVcopy(ag->npos, &RcLocation.X); dtVcopy(ag->vel, &RcVelocity.X); if (AgentData.bWantsPathOptimization) { AgentData.PathOptRemainingTime -= DeltaTime; if (AgentData.PathOptRemainingTime > 0) { ag->params.updateFlags &= ~DT_CROWD_OPTIMIZE_VIS; } else { ag->params.updateFlags |= DT_CROWD_OPTIMIZE_VIS; AgentData.PathOptRemainingTime = PathOptimizationInterval; } } }
void UCrowdManager::AddAgent(const ICrowdAgentInterface* Agent, FCrowdAgentData& AgentData) const { SCOPE_CYCLE_COUNTER(STAT_AI_Crowd_AgentUpdateTime); dtCrowdAgentParams Params; GetAgentParams(Agent, Params); // store for updating with constant intervals AgentData.bWantsPathOptimization = (Params.updateFlags & DT_CROWD_OPTIMIZE_VIS) != 0; // create link filter for fully simulated agents // (used to determine if agent can traverse smart links) TSharedPtr<dtQuerySpecialLinkFilter> MyLinkFilter; const UCrowdFollowingComponent* CrowdComponent = Cast<const UCrowdFollowingComponent>(Agent); if (CrowdComponent) { UNavigationSystem* NavSys = Cast<UNavigationSystem>(GetOuter()); MyLinkFilter = MakeShareable(new FRecastSpeciaLinkFilter(NavSys, CrowdComponent->GetOuter())); } Params.linkFilter = MyLinkFilter; const FVector RcAgentPos = Unreal2RecastPoint(Agent->GetCrowdAgentLocation()); const dtQueryFilter* DefaultFilter = ((const FRecastQueryFilter*)MyNavData->GetDefaultQueryFilterImpl())->GetAsDetourQueryFilter(); AgentData.AgentIndex = DetourCrowd->addAgent(&RcAgentPos.X, Params, DefaultFilter); AgentData.bIsSimulated = (Params.collisionQueryRange > 0.0f) && (CrowdComponent == NULL || CrowdComponent->IsCrowdSimulationEnabled()); AgentData.LinkFilter = MyLinkFilter; }
bool UCrowdManager::SetAgentMoveTarget(const UCrowdFollowingComponent* AgentComponent, const FVector& MoveTarget, FSharedConstNavQueryFilter Filter) const { SCOPE_CYCLE_COUNTER(STAT_AI_Crowd_AgentUpdateTime); bool bSuccess = false; #if WITH_RECAST const FCrowdAgentData* AgentData = ActiveAgents.Find(AgentComponent); if (AgentData && AgentData->bIsSimulated && AgentData->IsValid() && DetourCrowd) { FNavLocation ProjectedLoc; MyNavData->ProjectPoint(MoveTarget, ProjectedLoc, MyNavData->GetDefaultQueryExtent(), Filter); const INavigationQueryFilterInterface* NavFilter = Filter.IsValid() ? Filter->GetImplementation() : MyNavData->GetDefaultQueryFilterImpl(); const dtQueryFilter* DetourFilter = ((const FRecastQueryFilter*)NavFilter)->GetAsDetourQueryFilter(); DetourCrowd->updateAgentFilter(AgentData->AgentIndex, DetourFilter); DetourCrowd->updateAgentState(AgentData->AgentIndex, false); const FVector RcTargetPos = Unreal2RecastPoint(MoveTarget); bSuccess = DetourCrowd->requestMoveTarget(AgentData->AgentIndex, ProjectedLoc.NodeRef, &RcTargetPos.X); } #endif return bSuccess; }
void UCrowdManager::PostMovePointUpdate() { #if WITH_RECAST const uint8 UpdateDestinationFlag = 1; // special case when following last segment of full path to actor: replace end point with actor's location for (auto It : ActiveAgents) { UCrowdFollowingComponent* PathComp = Cast<UCrowdFollowingComponent>(It.Key); const FCrowdAgentData& AgentData = It.Value; FVector NewGoalPosition; const bool bUpdateTargetPos = PathComp ? PathComp->ShouldTrackMovingGoal(NewGoalPosition) : false; if (bUpdateTargetPos && AgentFlags.IsValidIndex(AgentData.AgentIndex)) { PathComp->UpdateDestinationForMovingGoal(NewGoalPosition); const dtCrowdAgent* Agent = DetourCrowd->getAgent(AgentData.AgentIndex); dtCrowdAgent* MutableAgent = (dtCrowdAgent*)Agent; const FVector RcTargetPos = Unreal2RecastPoint(NewGoalPosition); dtVcopy(MutableAgent->targetPos, &RcTargetPos.X); AgentFlags[AgentData.AgentIndex] |= UpdateDestinationFlag; } } dtCrowdAgent** ActiveDetourAgents = DetourCrowd->getActiveAgents(); for (int32 Idx = 0; Idx < DetourCrowd->getNumActiveAgents(); Idx++) { dtCrowdAgent* Agent = ActiveDetourAgents[Idx]; if (Agent->state == DT_CROWDAGENT_STATE_WALKING && Agent->ncorners == 1 && Agent->corridor.getPathCount() < 5 && (Agent->cornerFlags[0] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) == 0) { const int32 AgentIndex = DetourCrowd->getAgentIndex(Agent); if (AgentFlags.IsValidIndex(AgentIndex) && (AgentFlags[AgentIndex] & UpdateDestinationFlag) != 0) { dtVcopy(Agent->cornerVerts, Agent->targetPos); } } } for (auto It : ActiveAgents) { const FCrowdAgentData& AgentData = It.Value; if (AgentFlags.IsValidIndex(AgentData.AgentIndex)) { AgentFlags[AgentData.AgentIndex] &= ~UpdateDestinationFlag; } } #endif }
bool UCrowdManager::SetAgentMovePath(const UCrowdFollowingComponent* AgentComponent, const FNavMeshPath* Path, int32 PathSectionStart, int32 PathSectionEnd, const FVector& PathSectionEndLocation) const { SCOPE_CYCLE_COUNTER(STAT_AI_Crowd_AgentUpdateTime); bool bSuccess = false; #if WITH_RECAST const FCrowdAgentData* AgentData = ActiveAgents.Find(AgentComponent); ARecastNavMesh* RecastNavData = Cast<ARecastNavMesh>(MyNavData); if (AgentData && AgentData->bIsSimulated && AgentData->IsValid() && DetourCrowd && RecastNavData && Path && (Path->GetPathPoints().Num() > 1) && Path->PathCorridor.IsValidIndex(PathSectionStart) && Path->PathCorridor.IsValidIndex(PathSectionEnd)) { FVector TargetPos = PathSectionEndLocation; if (PathSectionEnd < (Path->PathCorridor.Num() - 1)) { RecastNavData->GetPolyCenter(Path->PathCorridor[PathSectionEnd], TargetPos); } TArray<dtPolyRef> PathRefs; for (int32 Idx = PathSectionStart; Idx <= PathSectionEnd; Idx++) { PathRefs.Add(Path->PathCorridor[Idx]); } const INavigationQueryFilterInterface* NavFilter = Path->GetFilter().IsValid() ? Path->GetFilter()->GetImplementation() : MyNavData->GetDefaultQueryFilterImpl(); const dtQueryFilter* DetourFilter = ((const FRecastQueryFilter*)NavFilter)->GetAsDetourQueryFilter(); DetourCrowd->updateAgentFilter(AgentData->AgentIndex, DetourFilter); DetourCrowd->updateAgentState(AgentData->AgentIndex, false); const FVector RcTargetPos = Unreal2RecastPoint(TargetPos); bSuccess = DetourCrowd->requestMoveTarget(AgentData->AgentIndex, PathRefs.Last(), &RcTargetPos.X); if (bSuccess) { bSuccess = DetourCrowd->setAgentCorridor(AgentData->AgentIndex, PathRefs.GetData(), PathRefs.Num()); } } #endif return bSuccess; }
bool UCrowdManager::SetAgentMoveDirection(const UCrowdFollowingComponent* AgentComponent, const FVector& MoveDirection) const { SCOPE_CYCLE_COUNTER(STAT_AI_Crowd_AgentUpdateTime); bool bSuccess = false; #if WITH_RECAST const FCrowdAgentData* AgentData = ActiveAgents.Find(AgentComponent); if (AgentData && AgentData->bIsSimulated && AgentData->IsValid() && DetourCrowd) { DetourCrowd->updateAgentState(AgentData->AgentIndex, false); const FVector RcTargetVelocity = Unreal2RecastPoint(MoveDirection * AgentComponent->GetCrowdAgentMaxSpeed()); bSuccess = DetourCrowd->requestMoveVelocity(AgentData->AgentIndex, &RcTargetVelocity.X); } #endif return bSuccess; }
ENGINE_API FBox Unreal2RecastBox(const FBox& UnrealBox) { FVector Points[2] = { Unreal2RecastPoint(UnrealBox.Min), Unreal2RecastPoint(UnrealBox.Max) }; return FBox(Points, 2); }