🎮
「UnrealEngine」最寄りのナビメッシュ上の座標を取得する
必要になった背景
- ナビメッシュで経路探索をする際に
UNavigationSystemV1::FindPathToLocationSynchronously
( UObject* WorldContextObject,
const FVector& PathStart,
const FVector& PathEnd,
AActor* PathfindingContext,
TSubclassOf<UNavigationQueryFilter> FilterClass
)
- この関数のみでパス検索すると、終点がナビメッシュの外に出たとき(キャラが空中に浮いたりとかした場合)に、パスの作成に失敗してしまう。そのためこの関数で指定した終点がメッシュ内になるようにしたかった。
解決方法
UNavigationSystemV1::ProjectPointToNavigation
( const FVector& Point,
FNavLocation& OutLocation,
const FVector& Extent = INVALID_NAVEXTENT,
const FNavAgentProperties* AgentProperties = NULL,
FSharedConstNavQueryFilter QueryFilter = NULL
)
- この関数を使用すると Extent で指定した範囲内の最寄りの終点位置が FNavLocation& で取れる。結果を取り出す際は
FNavLocation::Location
- で取得できるので、この値を FindPathToLocationSynchronously() の PathEnd に指定する。
#include "NavigationSystem.h"
#include "NavigationPath.h"
//~~~~
void ASample::FindPath(const FVector& endPoint)
{
const auto owner = GetOwner();
if (!IsValid(owner))
{
return;
}
UNavigationSystemV1* NavSys = UNavigationSystemV1::GetCurrent(GetWorld());
// endPointから最寄りのMeshの検索範囲
const FVector Extent(500, 500, 10000);
// 巨大なアクター等だと開始地点がうまく取得できないのでExtentで位置を取得する
FNavLocation StartPathLocation;
// メッシュからはみ出た位置を指定すると終了地点がうまく取得できないのでExtentで位置を取得する
FNavLocation EndPathLocation;
// 最寄りのナビメッシュ上の座標が取れる
NavSys->ProjectPointToNavigation(owner->GetActorLocation(), StartPathLocation, Extent);
NavSys->ProjectPointToNavigation(endPoint, EndPathLocation, Extent);
NavPath = NavSys->FindPathToLocationSynchronously(GetWorld(), StartPathLocation.Location, EndPathLocation.Location);
#if WITH_EDITOR
// 以下の処理はデバッグ用の表示のみ
if (IsValid(NavPath))
{
float green_hue = 1.0f / 3.0f; // Normalized hue for green
float red_hue = 0.0f; // Normalized hue for red
float saturation = 1.0f; // Full saturation
float brightness = 1.0f; // Full brightness
for (int point = 0; point < NavPath->PathPoints.Num(); ++point)
{
// Calculate the hue based on the point index, interpolating between green and red
float Hue = FMath::Lerp(green_hue, red_hue, static_cast<float>(point) / (NavPath->PathPoints.Num() - 1));
// Create an FLinearColor from HSV values
FLinearColor PointColorHSV = FLinearColor::MakeFromHSV8(Hue * 255, saturation * 255, brightness * 255);
// Convert to FColor
FColor PointColor = PointColorHSV.ToFColor(true);
// Use the color for the current point
DrawDebugSphere(
GetWorld(),
NavPath->PathPoints[point],
10.0f,
12,
PointColor,
false,
0.01f
);
// If this is not the first point, draw a line from the previous point to the current one
if (point > 0)
{
// Interpolate the hue for the line color based on the previous point
float LineHue = FMath::Lerp(green_hue, red_hue, static_cast<float>(point - 1) / (NavPath->PathPoints.Num() - 1));
FLinearColor LineColorHSV = FLinearColor::MakeFromHSV8(LineHue * 255, saturation * 255, brightness * 255);
FColor LineColor = LineColorHSV.ToFColor(true);
// Draw the line
DrawDebugLine(
GetWorld(),
NavPath->PathPoints[point - 1],
NavPath->PathPoints[point],
LineColor,
false, 0.01f, 0,
5.0f // Thickness
);
}
}
}
#endif
}
Discussion