Using Points of Interest

Points of interest are objects that allow you to spatialize custom data into the NavMesh at given positions, and to quickly retrieve the points that lie within a particular region of space.

Each instance of the PointOfInterest class maintains an integer ID that you can set to identify a type of object or data that it represents in your game (i.e. to identify it as a cover point, a sniping point, etc.), and a void pointer that you can set to refer to particular objects in your game (i.e. to a weapon or ammo object, a health pack, etc.).

Points of interest are managed entirely at runtime; they are not part of the data generation process that pre-generates the NavMeshes for your terrain. You can create points of interest at runtime whenever you need them, move them to new positions if necessary, and retrieve them using a spatial query.

Game-side class

You need to set up a class in your game to manage the initialization and destruction of the PointOfInterest. You may already have a class in your game that manages the lifespan of the object that the PointOfInterest is intended to represent within the Autodesk Navigation World. If you do, you can use that class.

For example: [code from 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;
    ...
};

Initialization

To initialize your PointOfInterest, you must provide an instance of the PointOfInterestInitConfig configuration class, which you set up with the data needed by the PointOfInterest. You must set up at a minimum:

For example: [code from 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);
    ...
}

Updates

Each time the object represented by the PointOfInterest changes its position or other data in your game, you need to update your PointOfInterest to reflect the new state. You can use the PointofInterest::SetPosition() function to reflect the new state.

Note that this does not modify the PointOfInterest immediately; the update is deferred until the next update of the World.

For example: [code from Tutorial_PointOfInterest.cpp]

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

Destruction

To destroy the PointOfInterest:

For example: [code from Tutorial_PointOfInterest.cpp]

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

Retrieving points of interest

Points of interest are spatialized into the NavMesh using an internal SpatializedPoint object, the same mechanism used by other classes of spatialized WorldElements such as Bots and dynamic obstacles. You can create and launch an instance of the SpatializedPointCollectorInAABBQuery class in order to retrieve the spatialized points within a given bounding box.

By default, the query retrieves all kinds of spatialized points, but you can provide a filter for the query, so that your results will include only points of interest.

For example: [code from 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();
    ...

Once your query has been completed, you can iterate through the results to handle the points it retrieved. For example, this code pushes the ID of each point of interest to the visual debugging framework for rendering in the Navigation Lab: [code from Tutorial_PointOfInterest.cpp]

    ...

    Kaim::ScopedDisplayList displayList(database->GetWorld(), Kaim::DisplayList_Enable);
    displayList.InitSingleFrameLifespan("Nearby POIs", "Tutorial_PointOfInterest");
    Kaim::ShapeColor 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());
                    }
                }
            }
        }
    }
}