UE4的navlink proxy

一、导航数据的构造

导航数据的主体来自几何图形,但是离线联通就不是来自几何图形,所以要额外处理。从软件实现的角度看,这个额外处理要具有通用性。UE通用是通过INavRelevantInterface和FNavigationRelevantData来实现,两个结构的名字也非常直观,一个是“导航相关接口”,一个是“导航相关数据”,并且INavRelevantInterface的GetNavigationData接口负责填充FNavigationRelevantData数据。
Engine\Source\Runtime\NavigationSystem\Private\NavigationOctree.cpp
void FNavigationOctree::AppendToNode(const FOctreeElementId2& Id, INavRelevantInterface* NavElement, const FBox& Bounds, FNavigationOctreeElement& Element)
{
……
if (NavElement)
{
SCOPE_CYCLE_COUNTER(STAT_Navigation_GatheringNavigationModifiersSync);
const bool bDoInstantGathering = !IsLazyGathering(*NavElement);

if (bDoInstantGathering)
{
NavElement->GetNavigationData(*Element.Data);
}
else
{
Element.Data->bPendingChildLazyModifiersGathering = true;
}
}
……
}

二、ANavLinkProxy

可以看到,ANavLinkProxy类派生自INavRelevantInterface,所以它也提供了生成导航数据相关的接口。
class AIMODULE_API ANavLinkProxy : public AActor, public INavLinkHostInterface, public INavRelevantInterface
其中比较关系的接口就是GetNavigationData接口,这个接口的实现比较简单
void ANavLinkProxy::GetNavigationData(FNavigationRelevantData& Data) const
{
NavigationHelper::ProcessNavLinkAndAppend(&Data.Modifiers, this, PointLinks);
NavigationHelper::ProcessNavLinkSegmentAndAppend(&Data.Modifiers, this, SegmentLinks);
}
可以看到,它只是简单的把PointLinks(也就是SimpleLinks)节点添加到导航数据中,这些对应Details面板中的联通点信息。这里要注意的是,Smart Link对应的数据在这里没有做任何处理。

三、SmartLink的处理

在Actor的Details面板上看到的SmartLink组件对应的类成员为
UNavLinkCustomComponent* SmartLinkComp;
从派生关系上看,UNavLinkCustomComponent派生自UNavRelevantComponent,也就是一个组件对象。
class NAVIGATIONSYSTEM_API UNavLinkCustomComponent : public UNavRelevantComponent, public INavLinkCustomInterface
组件对象有一个优点,就是可以运行时注册/卸载。这也是文档中提到的smart links的特点
Smart Links
Disabled by default
Turn on by ticking Smart Link Is Relevant
Can be turned on and off at runtime
And will notify nearby actors who want to know!
在组件注册的回调函数中
UNavLinkCustomComponent::OnRegister===>>>UNavigationSystemV1::RequestCustomLinkRegistering===>>>UNavigationSystemV1::RegisterCustomLink===>>>
CustomLinksMap.Add(LinkId, FNavigationSystem::FCustomLinkOwnerInfo(&CustomLink));
CustomLinksMap包含的INavLinkCustomInterface接口中有
/** Get basic link data: two points (relative to owner) and direction */
virtual void GetLinkData(FVector& LeftPt, FVector& RightPt, ENavLinkDirection::Type& Direction) const {};
可以获得Link的两个点和方向,这个也是smartlink中最为关键的两个维度。
UNavLinkCustomComponent类也继承了INavLinkCustomInterface接口,当通过INavLinkCustomInterface接口获得联通数据时,也是通过GetLinkData获得的,所以这个是获得Link的唯一入口。UNavLinkCustomComponent::GetNavigationData===>>>UNavLinkCustomComponent::GetLinkModifier===>>>INavLinkCustomInterface::GetModifier
FNavigationLink INavLinkCustomInterface::GetModifier(const INavLinkCustomInterface* CustomNavLink)
{
FNavigationLink LinkMod;
LinkMod.SetAreaClass(CustomNavLink->GetLinkAreaClass());
LinkMod.UserId = CustomNavLink->GetLinkId();

ENavLinkDirection::Type LinkDirection = ENavLinkDirection::BothWays;
CustomNavLink->GetLinkData(LinkMod.Left, LinkMod.Right, LinkDirection);
CustomNavLink->GetSupportedAgents(LinkMod.SupportedAgents);
LinkMod.Direction = LinkDirection;

return LinkMod;
}

四、通知到达特定位置

在smart link注册的时候,会为它生成唯一的userid
void UNavLinkCustomComponent::OnRegister()
{
Super::OnRegister();

if (NavLinkUserId == 0)
{
NavLinkUserId = INavLinkCustomInterface::GetUniqueId();
UE_LOG(LogNavLink, VeryVerbose, TEXT("%s new navlink id %u [%s]."), ANSI_TO_TCHAR(__FUNCTION__), NavLinkUserId, *GetFullName());
}

UNavigationSystemV1::RequestCustomLinkRegistering(*this, this);
}

在寻路的时候如果用到了这些节点,并且判断这些离线link的userid有效,则可以发送通知。
void UPathFollowingComponent::SetMoveSegment(int32 SegmentStartIndex)
{
……
// handle moving through custom nav links
if (PathPt0.CustomLinkId)
{
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
INavLinkCustomInterface* CustomNavLink = NavSys->GetCustomLink(PathPt0.CustomLinkId);
StartUsingCustomLink(CustomNavLink, SegmentEnd);
}
……
}

五、offmesh link路径点的标志

bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
{
……
if (offMeshCon.type & DT_OFFMESH_CON_POINT)
{
dtPoly* p = &navPolys[offMeshPolyBase+n];
p->vertCount = 2;
p->verts[0] = (unsigned short)(offMeshVertsBase + n*2+0);
p->verts[1] = (unsigned short)(offMeshVertsBase + n*2+1);
p->flags = offMeshCon.polyFlag;
p->setArea(offMeshCon.area);
p->setType(DT_POLYTYPE_OFFMESH_POINT);
n++;
}
……
}

六、smart和simple的关系

两者本质上是没什么必然联系的,它们可以同时存在,也可以同时被寻路系统使用(这个结论没有真正验证)。

 

posted on 2021-11-09 18:31  tsecer  阅读(948)  评论(0编辑  收藏  举报

导航