Ejemplo n.º 1
0
FAIRequestID AAIController::RequestPathAndMove(const FAIMoveRequest& MoveRequest, FPathFindingQuery& Query)
{
	FAIRequestID RequestID;

	UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
	if (NavSys)
	{
		FPathFindingResult PathResult = NavSys->FindPathSync(Query);
		if (PathResult.Result != ENavigationQueryResult::Error)
		{
			if (PathResult.IsSuccessful() && PathResult.Path.IsValid())
			{
				if (MoveRequest.IsUsingPathfinding())
				{
					if (MoveRequest.HasGoalActor())
					{
						PathResult.Path->SetGoalActorObservation(*MoveRequest.GetGoalActor(), 100.0f);
					}

					PathResult.Path->EnableRecalculationOnInvalidation(true);
				}

				RequestID = RequestMove(MoveRequest, PathResult.Path);
			}
		}
		else
		{
			UE_VLOG(this, LogAINavigation, Error, TEXT("Trying to find path to %s resulted in Error"), *GetNameSafe(MoveRequest.GetGoalActor()));
		}
	}

	return RequestID;
}
Ejemplo n.º 2
0
void AAIController::FindPathForMoveRequest(const FAIMoveRequest& MoveRequest, FPathFindingQuery& Query, FNavPathSharedPtr& OutPath) const
{
    SCOPE_CYCLE_COUNTER(STAT_AI_Overall);

    UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
    if (NavSys)
    {
        FPathFindingResult PathResult = NavSys->FindPathSync(Query);
        if (PathResult.Result != ENavigationQueryResult::Error)
        {
            if (PathResult.IsSuccessful() && PathResult.Path.IsValid())
            {
                if (MoveRequest.IsMoveToActorRequest())
                {
                    PathResult.Path->SetGoalActorObservation(*MoveRequest.GetGoalActor(), 100.0f);
                }

                PathResult.Path->EnableRecalculationOnInvalidation(true);
                OutPath = PathResult.Path;
            }
        }
        else
        {
            UE_VLOG(this, LogAINavigation, Error, TEXT("Trying to find path to %s resulted in Error")
                    , MoveRequest.IsMoveToActorRequest() ? *GetNameSafe(MoveRequest.GetGoalActor()) : *MoveRequest.GetGoalLocation().ToString());
            UE_VLOG_SEGMENT(this, LogAINavigation, Error, GetPawn() ? GetPawn()->GetActorLocation() : FAISystem::InvalidLocation
                            , MoveRequest.GetGoalLocation(), FColor::Red, TEXT("Failed move to %s"), *GetNameSafe(MoveRequest.GetGoalActor()));
        }
    }
}
Ejemplo n.º 3
0
FAIRequestID AAIController::RequestPathAndMove(FPathFindingQuery& Query, AActor* Goal, float AcceptanceRadius, bool bStopOnOverlap, FCustomMoveSharedPtr CustomData)
{
	FAIRequestID RequestID;

	UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
	if (NavSys)
	{
		FPathFindingResult PathResult = NavSys->FindPathSync(Query);
		if (PathResult.Result != ENavigationQueryResult::Error)
		{
			if (PathResult.IsSuccessful() && PathResult.Path.IsValid())
			{
				if (Goal)
				{
					PathResult.Path->SetGoalActorObservation(*Goal, 100.0f);
				}

				PathResult.Path->EnableRecalculationOnInvalidation(true);
			}

			RequestID = RequestMove(PathResult.Path, Goal, AcceptanceRadius, bStopOnOverlap, CustomData);
		}
		else
		{
			UE_VLOG(this, LogBehaviorTree, Error, TEXT("Trying to find path to %s resulted in Error"), *GetNameSafe(Goal));
		}
	}

	return RequestID;
}
void ANavigationTestingActor::SearchPathTo(ANavigationTestingActor* Goal)
{
#if WITH_EDITORONLY_DATA
	if (EdRenderComp)
	{
		EdRenderComp->MarkRenderStateDirty();
	}
#endif // WITH_EDITORONLY_DATA

	if (Goal == NULL) 
	{
		return;
	}

	UNavigationSystem* NavSys = GetWorld()->GetNavigationSystem();
	check(NavSys);

	const double StartTime = FPlatformTime::Seconds();

	FPathFindingQuery Query = BuildPathFindingQuery(Goal);
	EPathFindingMode::Type Mode = bUseHierarchicalPathfinding ? EPathFindingMode::Hierarchical : EPathFindingMode::Regular;
	FPathFindingResult Result = NavSys->FindPathSync(NavAgentProps, Query, Mode);

	const double EndTime = FPlatformTime::Seconds();
	const float Duration = (EndTime - StartTime);
	PathfindingTime = Duration * 1000000.0f;			// in micro seconds [us]
	bPathIsPartial = Result.IsPartial();
	bPathExist = Result.IsSuccessful();
	bPathSearchOutOfNodes = bPathExist ? Result.Path->DidSearchReachedLimit() : false;
	LastPath = Result.Path;
	PathCost = bPathExist ? Result.Path->GetCost() : 0.0f;

	if (bPathExist)
	{
		LastPath->AddObserver(PathObserver);

		if (OffsetFromCornersDistance > 0.0f)
		{
			((FNavMeshPath*)LastPath.Get())->OffsetFromCorners(OffsetFromCornersDistance);
		}
	}

#if WITH_RECAST && WITH_EDITORONLY_DATA
	if (bGatherDetailedInfo && !bUseHierarchicalPathfinding)
	{
		ARecastNavMesh* RecastNavMesh = Cast<ARecastNavMesh>(MyNavData);
		if (RecastNavMesh && RecastNavMesh->HasValidNavmesh())
		{
			PathfindingSteps = RecastNavMesh->DebugPathfinding(Query, DebugSteps);
		}
	}
#endif
}
void UNavigationComponent::OnSmartLinkBroadcast(class USmartNavLinkComponent* NearbyLink)
{
	// update only when agent is actually moving
	if (NearbyLink == NULL || !Path.IsValid() ||
		PathFollowComp == NULL || PathFollowComp->GetStatus() == EPathFollowingStatus::Idle)
	{
		return;
	}

	UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
	if (NavSys == NULL || MyNavAgent == NULL || GetNavData() == NULL)
	{
		return;
	}

	const bool bHasLink = Path->ContainsSmartLink(NearbyLink);
	const bool bIsEnabled = NearbyLink->IsEnabled();
	if (bIsEnabled == bHasLink)
	{
		// enabled link, path already use it - or - disabled link and path it's not using it
		return;
	}

	const FVector GoalLocation = Path->PathPoints.Last().Location;

	FPathFindingResult Result = NavSys->FindPathSync(*MyNavAgent->GetNavAgentProperties(),
		FPathFindingQuery(GetNavData(), MyNavAgent->GetNavAgentLocation(), GoalLocation, StoredQueryFilter),
		bDoHierarchicalPathfinding ? EPathFindingMode::Hierarchical : EPathFindingMode::Regular);

	if (Result.IsSuccessful() || Result.IsPartial())
	{
		const bool bNewHasLink = Result.Path->ContainsSmartLink(NearbyLink);

		if ((bIsEnabled && !bHasLink && bNewHasLink) ||
			(!bIsEnabled && bHasLink && !bNewHasLink))
		{			
			SetPath(Result.Path);
			NotifyPathUpdate();
		}
	}
}
bool UNavigationComponent::GeneratePath(const FVector& FromLocation, const FVector& GoalLocation, TSharedPtr<const FNavigationQueryFilter> QueryFilter)
{
	if (GetWorld() == NULL || GetWorld()->GetNavigationSystem() == NULL || GetOuter() == NULL || MyNavAgent == NULL || GetNavData() == NULL)
	{
		return false;
	}

	const FNavLocation NavMeshGoalLocation = ProjectPointToNavigation(GoalLocation);
	const EPathFindingMode::Type Mode = bDoHierarchicalPathfinding ? EPathFindingMode::Hierarchical : EPathFindingMode::Regular;
	FPathFindingResult Result = GetWorld()->GetNavigationSystem()->FindPathSync(*MyNavAgent->GetNavAgentProperties()
		, FPathFindingQuery(GetNavData(), FromLocation, NavMeshGoalLocation.Location, QueryFilter)
		, Mode);

	if (Result.IsSuccessful() || Result.IsPartial())
	{
		CurrentGoal = NavMeshGoalLocation.Location;
		SetPath(Result.Path);
		return true;
	}

	return false;
}
bool UNavigationComponent::GeneratePathTo(const FVector& GoalLocation, TSharedPtr<const FNavigationQueryFilter> QueryFilter)
{
	if (GetWorld() == NULL || GetWorld()->GetNavigationSystem() == NULL || GetOuter() == NULL)
	{
		return false;
	}

	// Make sure we're trying to path to the closest valid location TO that location rather than the absolute location.
	// After talking with Steve P., if we need to ever allow pathing WITHOUT projecting to nav-mesh, it will probably be
	// best to do so using a flag while keeping this as the default behavior.  NOTE:` If any changes to this behavior
	// are made, you should search for other places in UNavigationComponent using NavMeshGoalLocation and make sure the
	// behavior remains consistent.
	
	// make sure that nav data is updated
	GetNavData();

	const FNavAgentProperties* NavAgentProps = MyNavAgent ? MyNavAgent->GetNavAgentProperties() : NULL;
	if (NavAgentProps != NULL)
	{
		FVector NavMeshGoalLocation;

#if ENABLE_VISUAL_LOG
		UE_VLOG_LOCATION(GetOwner(), GoalLocation, 34, FColor(0,127,14), TEXT("GoalLocation"));
		const FVector ProjectionExtent = MyNavData ? MyNavData->GetDefaultQueryExtent() : FVector(DEFAULT_NAV_QUERY_EXTENT_HORIZONTAL, DEFAULT_NAV_QUERY_EXTENT_HORIZONTAL, DEFAULT_NAV_QUERY_EXTENT_VERTICAL);
		UE_VLOG_BOX(GetOwner(), FBox(GoalLocation - ProjectionExtent, GoalLocation + ProjectionExtent), FColor::Green, TEXT_EMPTY);
#endif

		if (ProjectPointToNavigation(GoalLocation, NavMeshGoalLocation) == QuerySuccess)
		{
			UE_VLOG_SEGMENT(GetOwner(), GoalLocation, NavMeshGoalLocation, FColor::Blue, TEXT_EMPTY);
			UE_VLOG_LOCATION(GetOwner(), NavMeshGoalLocation, 34, FColor::Blue, TEXT_EMPTY);
			
			UNavigationSystem* NavSys = GetWorld()->GetNavigationSystem();
			FPathFindingQuery Query(MyNavData, MyNavAgent->GetNavAgentLocation(), NavMeshGoalLocation, QueryFilter);

			const EPathFindingMode::Type Mode = bDoHierarchicalPathfinding ? EPathFindingMode::Hierarchical : EPathFindingMode::Regular;
			FPathFindingResult Result = NavSys->FindPathSync(*MyNavAgent->GetNavAgentProperties(), Query, Mode);

			// try reversing direction
			if (bSearchFromGoalWhenOutOfNodes && !bDoHierarchicalPathfinding &&
				Result.Path.IsValid() && Result.Path->DidSearchReachedLimit())
			{
				// quick check if path exists
				bool bPathExists = false;
				{
					DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Pathfinding: HPA* test time"), STAT_Navigation_PathVerifyTime, STATGROUP_Navigation);
					bPathExists = NavSys->TestPathSync(Query, EPathFindingMode::Hierarchical);
				}

				UE_VLOG(GetOwner(), LogNavigation, Log, TEXT("GeneratePathTo: out of nodes, HPA* path: %s"),
					bPathExists ? TEXT("exists, trying reversed search") : TEXT("doesn't exist"));

				// reverse search
				if (bPathExists)
				{
					DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Pathfinding: reversed test time"), STAT_Navigation_PathReverseTime, STATGROUP_Navigation);

					TSharedPtr<FNavigationQueryFilter> Filter = QueryFilter.IsValid() ? QueryFilter->GetCopy() : MyNavData->GetDefaultQueryFilter()->GetCopy();					
					Filter->SetBacktrackingEnabled(true);

					FPathFindingQuery ReversedQuery(MyNavData, Query.EndLocation, Query.StartLocation, Filter);
					Result = NavSys->FindPathSync(*MyNavAgent->GetNavAgentProperties(), Query, Mode);
				}
			}

			if (Result.IsSuccessful() || Result.IsPartial())
			{
				CurrentGoal = NavMeshGoalLocation;
				SetPath(Result.Path);

				if (IsFollowing() == true)
				{
					// make sure ticking is enabled (and it shouldn't be enabled before _first_ async path finding)
					SetComponentTickEnabledAsync(true);
				}

				NotifyPathUpdate();
				return true;
			}
			else
			{
				UE_VLOG(GetOwner(), LogNavigation, Display, TEXT("Failed to generate path to destination"));
			}
		}
		else
		{
			UE_VLOG(GetOwner(), LogNavigation, Display, TEXT("Destination not on navmesh (and nowhere near!)"));
		}
	}
	else
	{
		UE_VLOG(GetOwner(), LogNavigation, Display, TEXT("UNavigationComponent::GeneratePathTo: NavAgentProps == NULL (Probably Pawn died)"));
	}

	return false;
}
Ejemplo n.º 8
0
void ANavigationData::TickActor(float DeltaTime, enum ELevelTick TickType, FActorTickFunction& ThisTickFunction)
{
	Super::TickActor(DeltaTime, TickType, ThisTickFunction);

	PurgeUnusedPaths();

	INC_DWORD_STAT_BY(STAT_Navigation_ObservedPathsCount, ObservedPaths.Num());

	if (NextObservedPathsTickInSeconds >= 0.f)
	{
		NextObservedPathsTickInSeconds -= DeltaTime;
		if (NextObservedPathsTickInSeconds <= 0.f)
		{
			RepathRequests.Reserve(ObservedPaths.Num());

			for (int32 PathIndex = ObservedPaths.Num() - 1; PathIndex >= 0; --PathIndex)
			{
				if (ObservedPaths[PathIndex].IsValid())
				{
					FNavPathSharedPtr SharedPath = ObservedPaths[PathIndex].Pin();
					FNavigationPath* Path = SharedPath.Get();
					EPathObservationResult::Type Result = Path->TickPathObservation();
					switch (Result)
					{
					case EPathObservationResult::NoLongerObserving:
						ObservedPaths.RemoveAtSwap(PathIndex, 1, /*bAllowShrinking=*/false);
						break;

					case EPathObservationResult::NoChange:
						// do nothing
						break;

					case EPathObservationResult::RequestRepath:
						RepathRequests.Add(FNavPathRecalculationRequest(SharedPath, ENavPathUpdateType::GoalMoved));
						break;
					
					default:
						check(false && "unhandled EPathObservationResult::Type in ANavigationData::TickActor");
						break;
					}
				}
				else
				{
					ObservedPaths.RemoveAtSwap(PathIndex, 1, /*bAllowShrinking=*/false);
				}
			}

			if (ObservedPaths.Num() > 0)
			{
				NextObservedPathsTickInSeconds = ObservedPathsTickInterval;
			}
		}
	}

	if (RepathRequests.Num() > 0)
	{
		float TimeStamp = GetWorldTimeStamp();
		TArray<FNavPathRecalculationRequest> PostponedRequests;
		const UWorld* World = GetWorld();

		// @todo batch-process it!
		for (auto RecalcRequest : RepathRequests)
		{
			// check if it can be updated right now
			FNavPathSharedPtr PinnedPath = RecalcRequest.Path.Pin();
			if (PinnedPath.IsValid() == false)
			{
				continue;
			}

			const UObject* PathQuerier = PinnedPath->GetQuerier();
			const INavAgentInterface* PathNavAgent = Cast<const INavAgentInterface>(PathQuerier);
			if (PathNavAgent && PathNavAgent->ShouldPostponePathUpdates())
			{
				PostponedRequests.Add(RecalcRequest);
				continue;
			}

			FPathFindingQuery Query(PinnedPath.ToSharedRef());
			// @todo consider supplying NavAgentPropertied from path's querier
			const FPathFindingResult Result = FindPath(FNavAgentProperties(), Query.SetPathInstanceToUpdate(PinnedPath));

			// update time stamp to give observers any means of telling if it has changed
			PinnedPath->SetTimeStamp(TimeStamp);

			// partial paths are still valid and can change to full path when moving goal gets back on navmesh
			if (Result.IsSuccessful() || Result.IsPartial())
			{
				PinnedPath->UpdateLastRepathGoalLocation();
				PinnedPath->DoneUpdating(RecalcRequest.Reason);
				if (RecalcRequest.Reason == ENavPathUpdateType::NavigationChanged)
				{
					RegisterActivePath(PinnedPath);
				}
			}
			else
			{
				PinnedPath->RePathFailed();
			}
		}

		RepathRequests.Reset();
		RepathRequests.Append(PostponedRequests);
	}
}