• 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的关系

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

  • 相关阅读:
    oracle 动态SQL
    Oracle 学习PL/SQL
    SQL优化原理
    JAVA环境配置
    Java接口
    Java数据类型、操作符、表达式
    C#-VS配置开发环境-摘
    Java版本
    网站构建
    Java 时间、字符串
  • 原文地址:https://www.cnblogs.com/tsecer/p/15530366.html
Copyright © 2020-2023  润新知