統合フェーズ 4: クエリを使用して実行時にパスを計算する

統合のこのフェーズでは、地形の 2 つのポイント間のパスを計算するためにクエリを使用する方法について学習します。ツールボックスのレイヤで提供されるクエリについて説明します。

Navigation Lab での作業

まず、Navigation Lab でクエリを実行する方法について説明します。

  1. Navigation Lab に .NavData ファイルをドラッグ & ドロップします。
  2. NavMesh でパスの開始位置を右クリックし、コンテキスト メニューから Set Marker A を選択します。
  3. パスの目的地を右クリックし、コンテキスト メニューから Set Marker B を選択します。

  4. Navigation Lab のメイン ウィンドウの左側にある Query Browser パネルを開き、Astar クエリを選択します。
  5. Navigation Lab のメイン ウィンドウの右側にある Attribute Editor パネルを開きます。ここでは、選択されたクエリのパラメータを設定することができます。

    Start コントロールと Dest コントロールをそれぞれ PosAPosB に設定します。これにより、位置 A のマーカから位置 B のマーカへのパスを計算するようクエリに対して指定します。

  6. これらの位置の間にパスがある場合は、3D ビューで緑色で表示されます。

Navigation Lab からは、簡単にクエリの開始点と終了点を取得することができます。Navigation Lab のメイン ウィンドウの下部には、3D 空間での A と B それぞれのマーカの位置が表示されます(Navigation 座標系で表されます)。これらの値をクリップボードにコピーするには、Copy ボタンをクリックします。

ゲーム コードでの作業

ここでは、AstarQuery クラスのインスタンスを使用して、実行時にゲームで同じクエリを複製します。

[Tutorial_FirstIntegration.cpp からのコード]

#include "gwnavruntime/queries/astarquery.h"
...

class MyGameLevel
{
public:
    ...    
    void Update(float deltaTimeInSeconds);
    ...
    void TestAStarQuery(Kaim::World* world);
    ...
protected:
    ...
    Kaim::Ptr<Kaim::AStarQuery<Kaim::DefaultTraverseLogic> >  m_astarQuery; // Not used for the entity, but simply to demonstrate how to run a query
    ...
};
...

bool MyGameLevel::Initialize(Kaim::World* world)
{ 
    ...
    m_astarQuery = *KY_NEW Kaim::AStarQuery<Kaim::DefaultTraverseLogic>;
    m_astarQuery->BindToDatabase(world->GetDatabase(0));
    ...
}
...

void MyGameLevel::TestAStarQuery(Kaim::World* world)
{
    // Choose two positions (in Navigation space) you want to test.
    // You can use the Navigation Lab to choose them.
    Kaim::Vec3f startPos = Kaim::Vec3f(-11.5963f,1.06987f,10.4563f);
    Kaim::Vec3f destPos  = Kaim::Vec3f(-16.636f,-26.7078f,8.10107f);

    // Leverage the visual debugging system.
    Kaim::ScopedDisplayList displayList(world, Kaim::DisplayList_Enable);
    displayList.InitSingleFrameLifespan("Test AStar Query", "My Game");
    displayList.PushLine(startPos, startPos + Kaim::Vec3f::UnitZ(), Kaim::VisualColor::Blue);
    displayList.PushLine(destPos,  destPos  + Kaim::Vec3f::UnitZ(), Kaim::VisualColor::Blue);

    if(m_astarQuery->m_processStatus == Kaim::QueryNotStarted)
    { 
        // Each AstarQuery must be set up to run on a specific Database. 
        m_astarQuery->Initialize(startPos, destPos);

        // Blocking means that we want the result immediately.
        // Alternatively, a query can be asynchronous and time-sliced. 
        m_astarQuery->PerformQueryBlocking();

    } else if (m_astarQuery->m_processStatus == Kaim::QueryDone)
    {
        // When the query is done, we ask for the result.
        Kaim::AStarQueryResult result = m_astarQuery->GetResult();

        // Kaim::AStarQueryResult enumerates many possible query results.
        // For now, let's focus on success.
        switch( result )
        {
        case Kaim::ASTAR_DONE_PATH_FOUND:
            {
                displayList.PushText(destPos + Kaim::Vec3f::UnitZ(), Kaim::VisualColor(0, 255, 0), "AStar query success !");
                break;
            }
        default:
            displayList.PushLine(startPos,  destPos , Kaim::VisualColor::Red);
            displayList.PushText(destPos + Kaim::Vec3f::UnitZ(), Kaim::VisualColor(255, 0, 0), "AStar query failed !");
            break;
        }

        // Here, we build and send a query, so it can be displayed into the NavigationLab.
        // cf. IQuery::SendVisualDebug() for more details.
        m_astarQuery->SendVisualDebug();
    }
}
...

void MyGameLevel::Update(float deltaTimeInSeconds)
{
    ...
    TestAStarQuery(m_entity.m_navBot->GetWorld());
    ...
}
...

void MyGameWorld::Update(float deltaTimeInSeconds)
{
    ...
    m_world->Update(deltaTimeInSeconds);
    m_gameLevel.Update(deltaTimeInSeconds);
}

再度 Navigation Lab での作業

ゲームに接続すると、3D ビューに、クエリによって計算されたパスが表示されます。NavMesh が同じであり、A マーカおよび B マーカに使用している位置も同じであるとすると、表示されるパスは Navigation Lab で最初にクエリを実行したときに表示されたものと同じになります。