在大多数项目中,预计您将把生成的 NavData 直接集成到自己的关卡设计工具或游戏编辑器中。此集成旨在确保当美工人员或设计人员对关卡进行更改时,最新的 NavData 始终自动生成并滚动到构建中。
请遵循集成阶段 1a:包含、库和预处理器定义中为运行时游戏提供的说明。此外,还必须链接 gwnavgeneration 库,该库与 gwnavruntime 位于同一目录。
在本教程中,DefaultGeneratorGlue 类将用于为生成系统提供并行处理服务。该类依赖于来自 Intel 的线程构建块 (TBB) 库在多个处理器间分布计算。要避免在 Gameware Navigation SDK 的核心库内引入第三方依存关系,该类及其相关类的头文件和源代码应保留在 integration 目录下。要使用 DefaultGeneratorGlue,您必须执行如下操作:
您必须编写 GeneratorInputProducer 类的实现。该类的目的是为 NavData 生成系统提供构成地形的三角形。
它包含一个您必须实现的关键虚拟方法:GeneratorInputProducer::Produce()。生成系统每次为地形的某个地块生成 NavData 时,都会调用该方法,从而传递要处理的地块说明以及向其提供三角形的 ClientInputConsumer 对象。GeneratorInputProducer::Produce() 的实现可以使用保留在 GeneratorSector 参数中的任何数据来确定应提供哪些三角形,包括创建该地块时为其指定的名称或 GUID。
有关将 NavData 分割为地块的详细信息,请参见将地形划分为地块。如果要创建可反映整个游戏地形的单个 NavData 地块(这可能是初始集成情况),GeneratorInputProducer::Produce() 的实现只需向 ClientInputConsumer 提供地形网格中的所有三角形。
#include "gwnavgeneration.h" class MyProducer : public Kaim::GeneratorInputProducer { public: virtual KyResult Produce( const Kaim::GeneratorSector& sector, Kaim::ClientInputConsumer& inputConsumer); }; KyResult MyProducer::Produce( const Kaim::GeneratorSector& /* sector */, Kaim::ClientInputConsumer& inputConsumer ) { // A sector can contain your whole level, or a part of a level that you plan // to stream in and out at runtime. You can set up as many sectors as you need. // See the section on running a generation below. // A NavTag is an array of blind data that you can add on each triangle. // You can use this data to distinguish different materials that you want to // take into account during your runtime path finding and path following. Kaim::DynamicNavTag aNavTag; aNavTag.m_blindDataArray.PushBack(42); // Set up a CoordSystem object to match the system used in your editor. KyFloat32 oneMeterInClientUnits = 1.0f; Kaim::CoordSystem::ClientAxis clientRightAxis = Kaim::CLIENT_X; Kaim::CoordSystem::ClientAxis clienFrontAxis = Kaim::CLIENT_Y; Kaim::CoordSystem::ClientAxis clientUpAxis = Kaim::CLIENT_Z; Kaim::CoordSystem myCoordSystem; myCoordSystem.Setup( oneMeterInClientUnits, clientRightAxis, clienFrontAxis, clientUpAxis ); // For each triangle in the sector, feed it to the input consumer. // How you retrieve the triangles is specific to your system. // If you have set up a CoordSystem as shown above, you can send your // triangles in your own coordinate system. The conversion is done internally // by the generation system. for(KyUInt32 index=0; index < myTriangleCount; index++) { inputConsumer.ConsumeTriangle( myTriangle.Vertex[0], myTriangle.Vertex[1], myTriangle.Vertex[2], aNavTag, myCoordSystem); } return KY_SUCCESS; }
ClientInputConsumer 对象还包含可在各个地块之间共享的种子点列表和 TagVolume 列表。如果需要提供具有种子点的生成系统或者在 3D 体积内标记 NavMesh,建议您将种子点和体积添加到这些列表中。有关详细信息,请参见标识可导航区域。
您需要初始化并关闭应用程序中的 BaseSystem,关闭方式与运行时游戏中相同。请参见集成阶段 1b:设置 BaseSystem。
您可以使用 GeneratorBaseSystem 类正确初始化生成 NavData 的 BaseSystem。如果不调用 Kaim::BaseSystem::Init(config),您可以简单调用 Kaim::GeneratorBaseSystem::Init(config)。在生成过程中,Gameware Navigation 使用仅对 NavData 生成有用的数据结构。因此,建议使用 GeneratorBaseSystem 以正确注册生成唯一的类。
启动生成运行所涉及的关键组件包括 Generator 类及其 GeneratorInputOutput 配置类。
创建 GeneratorInputOutput 对象,使用配置参数对其进行设置,并添加要为其生成 NavData 的地形的每个地块或地形块的定义。然后,在对 Generator::Generate() 的调用中传递此对象,从而启动生成过程。
#include "gwnavgenerationglue/defaultgeneratorglue.h" bool Generate() { // Create an instance of your GeneratorInputProducer class. Kaim::Ptr<MyProducer> producer = *KY_NEW MyProducer; // Create an instance of the DefaultGeneratorGlue. KyGlue::DefaultGeneratorGlue glue; // Set up a Generator to use your producer. Kaim::Generator generator(producer, &glue); // Set the output directory within which the .NavData and other output files // are created. You must use the same absolute root directory every time // you create a Generator, but you might set up a different relative directory for // each different level. This keeps all of your NavData easily accessible during // visual debugging. generator.SetOutputDirectory("c:/MyGame/NavData", "MyTestLevel"); // Create a GeneratorInputOutput Kaim::GeneratorInputOutput generatorInputOutput; // Alternatively, you can create a GeneratorInputOutput by loading it from a // .GenIO file created during a previous generation run. This retains all // settings from the last run. You can also explicitly save your GeneratorInputOutput // object at any time by calling Kaim::GeneratorInputOutput::Save(). // Use the Kaim::GeneratorParameters and Kaim::GeneratorAdvancedParameters // classes that are accessible through generatorInputOutput.m_params and // generatorInputOutput.m_params.m_advancedParameters to configure settings // such as, the dimensions and movemement capabilities of your characters. generatorInputOutput.m_params.m_entityRadius = 0.8f; generatorInputOutput.m_params.m_advancedParameters.m_navTagMinPixelArea = 4; // Use the Kaim::GeneratorRunOptions class that is accessible through // generatorInputOutput.m_runOptions to configure the operation of the // generation process itself. generatorInputOutput.m_runOptions. m_doMultiCore = true; // Add a sector. // It is recommended to create a unique GUID for each sector and // even to save it along with your own level definition. This ensures that you // always generate with the same GUID for a given level or block of terrain. // If you want to generate a random GUID, you can use the // KyGlue::DefaultGuidGeneratorInterface class. Kaim::Ptr<Kaim::GeneratorSector> sector = *KY_NEW Kaim::GeneratorSector( Kaim::KyGuid("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"), "MyGameLevel"); generatorInputOutput.AddSector(sector); // Run a generation using the configuration we have set up. if (Kaim::Result::Fail(generator.Generate(generatorInputOutput))) { return false; } return true; }
对于各个地块,生成系统提供了一组相同的输出文件作为 Navigation Lab。它们放在为 Generator 设置的根目录下的子目录中,并根据为 GeneratorSectorConfig 中的地块设置的名称进行命名。您可以从该位置检索 .NavData 文件,以便将其包含在您的游戏中。
使用输出文件的一种替代方法是检索作为原始数据缓冲区的 NavData,该数据可以与您关卡中的其他数据一起打包,以便在运行时游戏中简化数据进出内存的过程。请参见集成阶段 6a:将 NavData 集成到资源管线。