使用关注点

关注点是一种对象,允许您将自定义数据空间化到给定位置的 NavMesh 并快速检索位于特定空间区域的点。

PointOfInterest 类的每个实例均保留一个可设置为识别其在游戏中表示一种对象或数据类型(例如,识别为掩护点、狙击点等)的整数 ID 和一个可设置为在游戏中指向特定对象(例如,武器或弹药对象、急救箱等)的空指针。

关注点完全在运行时进行管理,而且它们不属于为您的地形预生成 NavMesh 的数据生成过程。您可以在运行时根据需要创建关注点,在需要时将其移动到新的位置,以及使用空间查询对其进行检索。

游戏端类

您需要在游戏中设置一个类来管理 PointOfInterest 的初始化和销毁。您的游戏中可能已经有一个类在管理 PointOfInterest 计划在 Gameware Navigation 世界中表示的对象或玩家角色的寿命。如果是这样,则可以使用该类。

例如:[Tutorial_PointOfInterest.cpp 中的代码]

class MyGamePointOfInterest
{
public:
    MyGamePointOfInterest() : m_navPointOfInterest(KY_NULL) {}

    void Initialize(Kaim::World* world, const Kaim::Vec3f& position);
    void Destroy();

    void SetPosition(const Kaim::Vec3f& newPosition);

    Kaim::Ptr<Kaim::PointOfInterest> m_navPointOfInterest;
    ...
};

初始化

要初始化 PointOfInterest,必须提供通过 PointOfInterest 所需数据设置的 PointOfInterestInitConfig 配置类的实例。您必须以最小值设置:

例如:[Tutorial_PointOfInterest.cpp 中的代码]

void MyGamePointOfInterest::Initialize(Kaim::World* world, const Kaim::Vec3f& position)
{
    ...
    // Set up the PointOfInterestInitConfig
    Kaim::PointOfInterestInitConfig pointOfInterestInitConfig;
    pointOfInterestInitConfig.m_world = world;
    pointOfInterestInitConfig.m_startPosition = position;
    pointOfInterestInitConfig.m_poiType = Kaim::PointOfInterestType_FirstClient;

    // Create and initialize the point of interest, and add it to its World
    m_navPointOfInterest = *KY_NEW Kaim::PointOfInterest;
    m_navPointOfInterest->Init(pointOfInterestInitConfig);
    m_navPointOfInterest->AddToWorld();

    // Set a pointer to your own data
    m_navPointOfInterest->SetUserData(this);
    ...
}

更新

每当 PointOfInterest 表示的对象在游戏中更改其位置或其他数据时,您需要更新 PointOfInterest 以反映新状态。您可以使用 PointofInterest::SetPosition() 函数反映新的状态。

请注意,此操作不会立即修改 PointOfInterest;更新将推迟到世界的下次更新。

例如:[Tutorial_PointOfInterest.cpp 中的代码]

void MyGamePointOfInterest::SetPosition(const Kaim::Vec3f& newPosition)
{
    m_navPointOfInterest->SetPosition(newPosition);
}

销毁

销毁 PointOfInterest

例如:[Tutorial_PointOfInterest.cpp 中的代码]

void MyGamePointOfInterest::Destroy()
{
    m_navPointOfInterest->RemoveFromWorld();
    m_navPointOfInterest = KY_NULL;
}

检索关注点

关注点将使用内部 SpatializedPoint 对象空间化到 NavMesh,空间化 WorldElement 的其他类(如人物和动态障碍物)也使用同一机制。您可以创建并启动 SpatializedPointCollectorInAABBQuery 类的实例,以检索给定包围盒内的空间化点。

默认情况下,查询将检索所有类型的空间化点,但您可以为查询使用过滤器,使结果仅包括关注点。

例如:[Tutorial_PointOfInterest.cpp 中的代码]

void CollectAndRenderNearbyPointsOfInterest(Kaim::Database* database, const Kaim::Vec3f& collectorBoxCenter, KyFloat32 collectorBoxHalfExtentFloat)
{
    ...

    // Set up a filter
    Kaim::SpatializedPointCollectorFilter_SelectiveCollect selectiveCollect;
    selectiveCollect.Select(Kaim::SpatializedPointObjectType_PointOfInterest);

    // Instantiate the query
    Kaim::SpatializedPointCollectorInAABBQuery<Kaim::SpatializedPointCollectorFilter_SelectiveCollect> query(selectiveCollect);
    query.BindToDatabase(database);

    // Set up the query parameters
    const Kaim::Vec3f collectorBoxHalfExtentVec3f(collectorBoxHalfExtentFloat, collectorBoxHalfExtentFloat, collectorBoxHalfExtentFloat);
    const Kaim::Box3f collectorBoxExtent(collectorBoxHalfExtentVec3f, collectorBoxHalfExtentVec3f);
    query.Initialize(collectorBoxCenter, collectorBoxExtent);

    // Perform the query
    query.PerformQueryBlocking();
    ...

查询完成后,您可以遍历结果,以处理查询所检索到的点。例如,此代码会将每个关注点的 ID 推入要在 Navigation Lab 中进行渲染的可视调试框架:[Tutorial_PointOfInterest.cpp 中的代码]

    ...

    Kaim::ScopedDisplayList displayList(database->GetWorld(), Kaim::DisplayList_Enable);
    displayList.InitSingleFrameLifespan("Nearby POIs", "Tutorial_PointOfInterest");
    Kaim::VisualShapeColor displayColor;
    displayColor.m_lineColor = Kaim::VisualColor::Magenta;
    displayList.PushBox(query.ComputeAABB(), displayColor);
    if (query.GetResult() == Kaim::SPATIALIZEDPOINTCOLLECTOR_DONE)
    {
        Kaim::QueryDynamicOutput* queryDynamicOutput = query.GetQueryDynamicOutput();
        if (queryDynamicOutput)
        {
            for(KyUInt32 i = 0; i < queryDynamicOutput->GetSpatializedPointCount(); ++i)
            {
                Kaim::SpatializedPoint* spatializedPoint = queryDynamicOutput->GetSpatializedPoint(i);
                if (spatializedPoint)
                {
                    const Kaim::Vec3f& position = spatializedPoint->GetPosition();
                    displayList.PushArrow(position + Kaim::Vec3f::UnitZ(), position, 0.1f, displayColor);
                    if (spatializedPoint->GetObjectType() == Kaim::SpatializedPointObjectType_PointOfInterest)
                    {
                        Kaim::StringStream displayText;
                        Kaim::PointOfInterest* pointOfInterest = (Kaim::PointOfInterest*)spatializedPoint->GetObject();
                        MyGamePointOfInterest* myGamePointOfInterest = (MyGamePointOfInterest*)pointOfInterest->GetUserData();
                        displayText << "   POI #" << myGamePointOfInterest->m_id;
                        displayList.PushText(position + Kaim::Vec3f::UnitZ(), Kaim::VisualColor::White, displayText.CStr());
                    }
                }
            }
        }
    }
}