コード例 #1
0
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();
		}
	}
}
コード例 #2
0
FNavLocation UNavigationComponent::ProjectPointToNavigation(const FVector& Location) const
{
	FNavLocation OutLocation(Location);
	
	if (GetNavData() != NULL)
	{
		if (!MyNavData->ProjectPoint(Location, OutLocation, MyNavData->GetDefaultQueryExtent()))
		{
			OutLocation = FNavLocation();
		}
	}

	return OutLocation;
}
コード例 #3
0
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;
}
コード例 #4
0
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;
}
コード例 #5
0
bool UNavigationComponent::AsyncGeneratePath(const FVector& FromLocation, const FVector& GoalLocation, TSharedPtr<const FNavigationQueryFilter> QueryFilter)
{
	if (GetWorld()->GetNavigationSystem() == NULL || GetOuter() == NULL || MyNavAgent == NULL || GetNavData() == 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.
	const FNavAgentProperties* NavAgentProps = MyNavAgent->GetNavAgentProperties();
	if (NavAgentProps != NULL)
	{
		FVector NavMeshGoalLocation;

		if (ProjectPointToNavigation(GoalLocation, NavMeshGoalLocation) == QuerySuccess)
		{
			const EPathFindingMode::Type Mode = bDoHierarchicalPathfinding ? EPathFindingMode::Hierarchical : EPathFindingMode::Regular;
			AsynPathQueryID = GetWorld()->GetNavigationSystem()->FindPathAsync(*MyNavAgent->GetNavAgentProperties()
				, FPathFindingQuery(MyNavData, FromLocation, NavMeshGoalLocation, QueryFilter)
				, FNavPathQueryDelegate::CreateUObject(this, &UNavigationComponent::AsyncGeneratePath_OnCompleteCallback)
				, Mode);
		}
		else
		{
			// projecting destination point failed
			AsynPathQueryID = INVALID_NAVQUERYID;

			UE_VLOG(GetOwner(), LogNavigation, Warning, TEXT("AI trying to generate path to point off of navmesh"));
			UE_VLOG_LOCATION(GetOwner(), GoalLocation, 30, FColor::Red, TEXT("Invalid pathing GoalLocation"));
			if (MyNavData != NULL)
			{
				UE_VLOG_BOX(GetOwner(), FBox(GoalLocation-MyNavData->GetDefaultQueryExtent(),GoalLocation+MyNavData->GetDefaultQueryExtent()), FColor::Red, TEXT_EMPTY);
			}
		}
	}
	else
	{
		AsynPathQueryID = INVALID_NAVQUERYID;
	}

	return AsynPathQueryID != INVALID_NAVQUERYID;
}
コード例 #6
0
bool UNavigationComponent::ProjectPointToNavigation(const FVector& Location, FNavLocation& ProjectedLocation) const
{
	return GetNavData() != NULL && MyNavData->ProjectPoint(Location, ProjectedLocation, MyNavData->GetDefaultQueryExtent());
}
コード例 #7
0
void UGameplayDebuggingComponent::ServerCollectNavmeshData_Implementation(FVector_NetQuantize10 TargetLocation)
{
#if WITH_RECAST
    UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
    ARecastNavMesh* NavData = GetNavData();
    if (NavData == NULL)
    {
        NavmeshRepData.Empty();
        return;
    }

    const double Timer1 = FPlatformTime::Seconds();

    TArray<int32> Indices;
    int32 TileX = 0;
    int32 TileY = 0;
    const int32 DeltaX[] = { 0, 1, 1, 0, -1, -1, -1,  0,  1 };
    const int32 DeltaY[] = { 0, 0, 1, 1,  1,  0, -1, -1, -1 };

    NavData->BeginBatchQuery();

    // add 3x3 neighborhood of target
    int32 TargetTileX = 0;
    int32 TargetTileY = 0;
    NavData->GetNavMeshTileXY(TargetLocation, TargetTileX, TargetTileY);
    for (int32 i = 0; i < ARRAY_COUNT(DeltaX); i++)
    {
        const int32 NeiX = TargetTileX + DeltaX[i];
        const int32 NeiY = TargetTileY + DeltaY[i];
        if (FMath::Abs(NeiX - TileX) > 1 || FMath::Abs(NeiY - TileY) > 1)
        {
            NavData->GetNavMeshTilesAt(NeiX, NeiY, Indices);
        }
    }

    const FNavDataConfig& NavConfig = NavData->GetConfig();
    FColor NavMeshColors[RECAST_MAX_AREAS];
    NavMeshColors[RECAST_DEFAULT_AREA] = NavConfig.Color.DWColor() > 0 ? NavConfig.Color : NavMeshRenderColor_RecastMesh;
    for (uint8 i = 0; i < RECAST_DEFAULT_AREA; ++i)
    {
        NavMeshColors[i] = NavData->GetAreaIDColor(i);
    }

    TArray<uint8> UncompressedBuffer;
    FMemoryWriter ArWriter(UncompressedBuffer);

    int32 NumIndices = Indices.Num();
    ArWriter << NumIndices;

    for (int32 i = 0; i < NumIndices; i++)
    {
        FRecastDebugGeometry NavMeshGeometry;
        NavMeshGeometry.bGatherPolyEdges = false;
        NavMeshGeometry.bGatherNavMeshEdges = false;
        NavData->GetDebugGeometry(NavMeshGeometry, Indices[i]);

        NavMeshDebug::FTileData TileData;
        const FBox TileBoundingBox = NavData->GetNavMeshTileBounds(Indices[i]);
        TileData.Location = TileBoundingBox.GetCenter();
        for (int32 VertIndex = 0; VertIndex < NavMeshGeometry.MeshVerts.Num(); ++VertIndex)
        {
            const NavMeshDebug::FShortVector SV = NavMeshGeometry.MeshVerts[VertIndex] - TileData.Location;
            TileData.Verts.Add(SV);
        }

        for (int32 iArea = 0; iArea < RECAST_MAX_AREAS; iArea++)
        {
            const int32 NumTris = NavMeshGeometry.AreaIndices[iArea].Num();
            if (NumTris)
            {
                NavMeshDebug::FAreaPolys AreaPolys;
                for (int32 AreaIndicesIndex = 0; AreaIndicesIndex < NavMeshGeometry.AreaIndices[iArea].Num(); ++AreaIndicesIndex)
                {
                    AreaPolys.Indices.Add(NavMeshGeometry.AreaIndices[iArea][AreaIndicesIndex]);
                }
                AreaPolys.Color = NavMeshColors[iArea];
                TileData.Areas.Add(AreaPolys);
            }
        }

        TileData.Links.Reserve(NavMeshGeometry.OffMeshLinks.Num());
        for (int32 iLink = 0; iLink < NavMeshGeometry.OffMeshLinks.Num(); iLink++)
        {
            const FRecastDebugGeometry::FOffMeshLink& SrcLink = NavMeshGeometry.OffMeshLinks[iLink];
            NavMeshDebug::FOffMeshLink Link;
            Link.Left = SrcLink.Left - TileData.Location;
            Link.Right = SrcLink.Right - TileData.Location;
            Link.Color = ((SrcLink.Direction && SrcLink.ValidEnds) || (SrcLink.ValidEnds & FRecastDebugGeometry::OMLE_Left)) ? DarkenColor(NavMeshColors[SrcLink.AreaID]) : NavMeshRenderColor_OffMeshConnectionInvalid;
            Link.PackedFlags.Radius = (int8)SrcLink.Radius;
            Link.PackedFlags.Direction = SrcLink.Direction;
            Link.PackedFlags.ValidEnds = SrcLink.ValidEnds;
            TileData.Links.Add(Link);
        }

        ArWriter << TileData;
    }
    NavData->FinishBatchQuery();

    const double Timer2 = FPlatformTime::Seconds();

    const int32 HeaderSize = sizeof(int32);
    NavmeshRepData.Init(0, HeaderSize + FMath::TruncToInt(1.1f * UncompressedBuffer.Num()));

    const int32 UncompressedSize = UncompressedBuffer.Num();
    int32 CompressedSize = NavmeshRepData.Num() - HeaderSize;
    uint8* DestBuffer = NavmeshRepData.GetData();
    FMemory::Memcpy(DestBuffer, &UncompressedSize, HeaderSize);
    DestBuffer += HeaderSize;

    FCompression::CompressMemory((ECompressionFlags)(COMPRESS_ZLIB | COMPRESS_BiasMemory),
                                 (void*)DestBuffer, CompressedSize, (void*)UncompressedBuffer.GetData(), UncompressedSize);

    NavmeshRepData.SetNum(CompressedSize + HeaderSize, false);

    const double Timer3 = FPlatformTime::Seconds();
    UE_LOG(LogGDT, Log, TEXT("Preparing navmesh data: %.1fkB took %.3fms (collect: %.3fms + compress %d%%: %.3fms)"),
           NavmeshRepData.Num() / 1024.0f, 1000.0f * (Timer3 - Timer1),
           1000.0f * (Timer2 - Timer1),
           FMath::TruncToInt(100.0f * NavmeshRepData.Num() / UncompressedBuffer.Num()), 1000.0f * (Timer3 - Timer2));
#endif

    if (World && World->GetNetMode() != NM_DedicatedServer)
    {
        OnRep_UpdateNavmesh();
    }
}