可视调试

此页面包含有关 Gameware Navigation 世界和 Navigation Lab 提供的可视调试系统的一些详细信息。

在游戏中使用可视调试系统

每个世界均包含一个内置的 VisualDebugServer 类实例。此类使用 Navigation Lab 管理所有运行时通信:

激活服务器

通过调用 World::StartVisualDebug()World 激活 VisualDebugServer

配置服务器

如果激活 VisualDebugServer,需要提供 VisualDebugServerConfig 配置对象。此配置对象包含若干可以根据需要进行设置的参数。

最重要的配置参数可能是端口设置 VisualDebugServerConfig::m_serverPortVisualDebugServerConfig::m_broadcastPort,它们可确定服务器将用来侦听传入连接并传播其可用性的端口。如果在将 Navigation Lab 连接到游戏时遇到问题,请确保这些端口已打开,或者在游戏中以及尝试连接到 Navigation Lab 时更改这些端口。

检索服务器

通过调用 World::GetVisualDebugServer()World 检索 VisualDebugServer

停止服务器

您可以随时通过调用 World::StopVisualDebug()World 停止 VisualDebugServer

WorldElement 的详细级别

衍生自 WorldElement 类的每个对象(例如人物、动态障碍物、TagVolume 和关注点)会在每一帧将数据通过网络自动发送到 Navigation Lab,以指示其当前位置、速度等信息。默认情况下,每个对象配置为仅发送最重要的常用信息项,例如其当前位置、尺寸、速度等。调试 Navigation Lab 中的游戏时,对于 Visual debug 面板中每一类的 WorldElement,可以选择要查看的项。

每种类型的对象还都可以将其他细节发送到 Navigation Lab;例如,人物可以发送关于它们的路径跟随和动态回避计算状态的详细信息。但是,为了避免过度占用游戏与 Navigation Lab 之间的网络通信带宽,默认情况下不发送这些详细信息。

如果需要查看可以为对象录制和发送的整个范围的数据,您可以在游戏代码中将该对象设置为使用最大详细级别 (LOD)。如果执行此操作,则该对象会在内部创建其他显示列表,并将其发送到 Navigation Lab 上显示。这些其他显示列表出现在 Visual debug 面板的 Display lists 标题下。但是,对于设置为使用最大细节层次的人物而言,其他显示列表大多出现在 Visual debug 面板中的 Bot 标题下。与任何其他显示列表类似,您可以显示或隐藏包含在其他显示列表中的数据。

设置详细级别

您可以随时通过调用其 SetCurrentVisualDebugLOD() 方法设置任何对象的 LoD。您可以传递以下任意级别:

  • VisualDebugLOD_None:不将有关对象的任何数据发送到 Navigation Lab。
  • VisualDebugLOD_Default:发送默认的可视调试信息。
  • VisualDebugLOD_Maximal:会将内部创建的提供有关对象的附加数据的其他显示列表发送到 Navigation Lab。

使用 ScopedDisplayList 渲染自定义 3D 数据

您可以通过设置 ScopedDisplayList 类的实例,将自己的 2D 图形和 3D 体积从游戏中发送到 Navigation Lab。

图形和体积

ScopedDisplayList 类的 API 提供了多种创建各种常用图形和体积的方法。

对于可视图例,请在 Navigation Lab 的命令行中输入以下命令:

ToggleDrawAllShapes

寿命

您创建的每个 ScopedDisplayList 仅发送到 Navigation Lab 一次(在用户创建的帧之后)。但是,每个显示列表都有指定的寿命,确定 Navigation Lab 会在多长时间内显示其数据。

寿命为单帧的显示列表仅在 Navigation Lab 从游戏中接收时渲染一次。为了使单帧显示列表中的数据能在 Navigation Lab 中跨多个帧持续显示,必须对每一帧重新创建新的 ScopedDisplayList 对象。此方法通常用于经常更改的数据。例如:

{
    Kaim::ScopedDisplayList displayList(navWorld);
    displayList.InitSingleFrameLifespan("Display list name", "Category name");
    displayList.PushLine(gameBot->GetPosition(), Kaim::Vec3f::Zero(), Kaim::VisualColor::White);
    ... // Add more shapes here
} // Here the ScopedDisplayList is sent to the Navigation Lab.

寿命为多帧的显示列表同样会发送到 Navigation Lab 一次,但它们会在这之后的每一帧中进行渲染,直到您对其进行修改或将其删除。如果您有数据在游戏玩法会话中保持静态,此方法可避免涉及在每个帧中重新创建该显示列表的计算,并节省在每个帧中重新发送显示列表所使用的网络带宽。

寿命为多帧的显示列表可通过提供的类别名称和显示列表名称组合,或通过 DisplayListManager 生成的数字 ID 唯一标识:

您可以使用该类别和名称组合或唯一 ID,以标识显示列表从而对其进行修改或将其删除:

例如,明确使用唯一 ID:

// Get a unique ID
m_displayListId = navWorld->GetDisplayListManager()->GenerateDisplayListId();

// Create a ScopedDisplayList:
{
    Kaim::ScopedDisplayList displayList(navWorld);
    m_displayListId = displayList.InitUserControlledLifespan("Display list name", "Category name", m_displayListId);
    displayList.PushLine(gameBot->GetPosition(), Kaim::Vec3f::Zero(), Kaim::VisualColor::White);
    ... // Add more shapes here
} // Here the ScopedDisplayList is sent to the Navigation Lab and rendered every frame.

...

// Modify the existing ScopedDisplayList:
{
    Kaim::ScopedDisplayList displayList(navWorld);
    m_displayListId = displayList.InitUserControlledLifespan("Display list name", "Category name", m_displayListId);
    ... // Add different shapes here
} // Here the ScopedDisplayList is sent to the NavigationLab, replacing the previous display list.

...

// Remove the existing ScopedDisplayList:
{
    navWorld->GetDisplayListManager()->RemoveDisplayList(m_displayListId); // The list is no longer displayed in the Navigation Lab.
}

在 Navigation Lab 中显示和隐藏显示列表

每次 Navigation Lab 在为游戏中的帧显示数据时,它会在 Visual debug 面板中的 Display lists 标题下列出对此帧有效的所有显示列表,并按您为显示列表提供的类别名称加以组织。您可以使用这些控件切换 3D 视图中每个显示列表的可见性。

例如,在下面的图像中,“MeleeCombat”为包含不同显示列表名称(“MeleeDistance”、“MeleeEdgeCollector”、“MeleeTarget”和“VisitedTriangles”)的显示列表所设置的类别名称。每个显示列表有自己的复选框,组织在共享类别名称下面。

将显示列表与 WorldElement 关联

您可以将 ScopedDisplayList 与特定 WorldElement(例如人物或动态障碍)相关联。当显示列表与 WorldElement 相关联时,可以控制此显示列表在 Navigation Lab 中的渲染以及该对象相关信息的其他项。

若要将 WorldElement 与 ScopedDisplayList 关联,请通过调用其 GetVisualDebugId () 方法检索 WorldElement 对象的 ID,并在 ScopedDisplayList 的初始化中提供该 ID。您仍然可以提供类别名称,该名称将用于在 Visual debug 面板中组织该 WorldElement 的显示列表。

对于用户控制的寿命的显示列表,如前面部分所述,您可以通过类别名称和显示名称的组合或通过明确指定唯一的 ID 来标识显示列表。

例如:

KyUInt32 worldElementId = m_gameBot->GetVisualDebugId();
displayList.InitSingleFrameLifespan("Display list name", "Category name", worldElementId);

KyUInt32 worldElementId = m_gameBot->GetVisualDebugId();
m_displayListId = displayList.InitUserControlledLifespan("Display list name", "Category name", worldElementId, m_displayListId);

跟随游戏摄影机

如果将游戏摄影机姿势和参数发送到可视调试器,您可以使 Navigation Lab 中 3D 视图下的摄影机跟随游戏摄影机的位置和方向。

要跟随游戏摄影机,请执行以下操作:

接受来自 Navigation Lab 的自定义命令

可在游戏中将 VisualDebugServer 设置为接受来自 Navigation Lab 中的命令行的自定义命令。这样可在调试期间在游戏中触发事件。

有关代码示例,请参见 Tutorial_VisualDebug.cpp 文件。