(UE4 4.20)UE4 如何判斷一個點是否在導航網格(Navigation)內

小毛狗發表於2019-01-05

在遊戲中經常碰到一個需求,就是在整個地圖具備導航網格的位置生成物品。

 

如下所示:綠色的部分就是具備導航網格的

 

那麼我們怎麼判斷一個點是否在導航網格內呢?(也就是一個點是否是圖中綠色的那些部分)

UE4提供了UNavigationSystemV1類,可以獲取各種導航網格資訊。這裡我們利用到一個介面:

bool ProjectPointToNavigation(const FVector& Point, FNavLocation& OutLocation, const FVector& Extent = INVALID_NAVEXTENT, const FNavAgentProperties* AgentProperties = NULL, FSharedConstNavQueryFilter QueryFilter = NULL)。

看下面原始碼:

bool ProjectPointToNavigation(const FVector& Point, FNavLocation& OutLocation, const FVector& Extent = INVALID_NAVEXTENT, const FNavAgentProperties* AgentProperties = NULL, FSharedConstNavQueryFilter QueryFilter = NULL)
{
	return ProjectPointToNavigation(Point, OutLocation, Extent, AgentProperties != NULL ? GetNavDataForProps(*AgentProperties) : GetDefaultNavDataInstance(FNavigationSystem::DontCreate), QueryFilter);
}



bool UNavigationSystemV1::ProjectPointToNavigation(const FVector& Point, FNavLocation& OutLocation, const FVector& Extent, const ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
{
	SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);

	if (NavData == NULL)
	{
		NavData = GetDefaultNavDataInstance();
	}

	return NavData != NULL && NavData->ProjectPoint(Point, OutLocation
		, FNavigationSystem::IsValidExtent(Extent) ? Extent : NavData->GetConfig().DefaultQueryExtent
		, QueryFilter);
}

我們採用的是第一個ProjectPointToNavigation介面,引數相對來說比較簡單。這裡主要用到前面三個引數:

const FVector& Point:我們要判斷的輸入的位置點

FNavLocation& OutLocation:我們要找到的導航網格點

FVector& Extent = INVALID_NAVEXTENT: 尋找的距離範圍

總體上的意思就是:我們在Point位置,以Extent為範圍的"Box內”, 尋找最近的導航網格點,如果找到則返回true,並且把這個最近的導航網格點存入OutLocation.反之如果找不到,則返回false,並且OutLocation 等於 Point點。

 

這裡比較注意的是:Extend如果為零向量,則Extend會變為另外一個預設的查詢Extend向量,看下面原始碼。其實這很好理解,因為如果Extend真的為0,那麼輸入的點恰好位於導航網格內才會返回true, 其實這是不科學的,因為很難恰好,座標位置相差0.1都不行。

return NavData != NULL && NavData->ProjectPoint(Point, OutLocation
		, FNavigationSystem::IsValidExtent(Extent) ? Extent : NavData->GetConfig().DefaultQueryExtent
		, QueryFilter);
namespace FNavigationSystem
{
	FORCEINLINE bool IsValidExtent(const FVector& Extent)
	{
		return Extent != INVALID_NAVEXTENT;
	}
}
#define INVALID_NAVEXTENT (FVector::ZeroVector)
USTRUCT(BlueprintType)
struct ENGINE_API FNavDataConfig : public FNavAgentProperties
{
	GENERATED_USTRUCT_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Display)
	FName Name;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Display)
	FColor Color;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Querying)
	FVector DefaultQueryExtent;

這個在引擎Setting裡面配置,預設是FVector(50, 50, 250)

 

下面是我的演示程式碼:

UCLASS()
class MYPROJECT3_API ATestNavMyActor : public AActor
{
	GENERATED_BODY()


	UPROPERTY(EditAnywhere)
		FVector extend;
}


void ATestNavMyActor::BeginPlay()
{
	Super::BeginPlay();
	
	UNavigationSystemV1* navigationSys = UNavigationSystemV1::GetCurrent(GetWorld());
	if (nullptr == navigationSys)
	{
		UE_LOG(LogTemp, Warning, TEXT("there is not navigation"));
		return;
	}
	FNavLocation navLocation;
	
	if (navigationSys->ProjectPointToNavigation(GetActorLocation(), navLocation, extend))
	{
		UE_LOG(LogTemp, Warning, TEXT("YES navigation location %s"), *navLocation.Location.ToString());
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("NO navigation location %s"), *navLocation.Location.ToString());
	}

	
}

 

Actor本身的位置:

Extend向量:

列印的位置,剛好位於與導航網格面的垂直Z軸上,如下所示

總結判斷一個點為導航網格點的辦法(有一點小誤差):

也就是設定一個比較小的Extend,如果ProjectPointToNavigation為true,則其為導航網格點

相關文章