There are many possible ways for you to customize the path following system for your characters, ranging from simple (such as calling class methods) to complex (re-implementing core classes). This topic, and the other topics in this section, outline some of the most common options and strategies for controlling the operation of the various elements of path following system.
Each Bot accepts a wide range of configuration parameters that control the way it finds and follows paths.
You can set your Bot configuration parameters in a BotConfig object, which you provide at initialization time in your call to Bot::Init(). This approach allows you to create and set up a single configuration object, which you can use to set up multiple game characters with an identical set of configuration parameters.
The BotConfig class contains some simple data members, and groups other parameters by functional category into subordinate configuration objects.
For example:
Kaim::BotConfig botConfig; botConfig.m_enableAvoidance = true; botConfig.m_shortcutTrajectoryConfig.m_maxDistanceFromBot = 20.0f; ... Kaim::Ptr<Kaim::Bot> bot = *KY_NEW Kaim::Bot(); bot->Init(botInitConfig, botConfig);
All of the configuration parameters in the BotConfig can also be set dynamically for each character, by calling methods of the Bot API.
Simple data members of the BotConfig are exposed directly through methods of the Bot class. For the subordinate configuration objects exposed by the BotConfig, the Bot class also exposes accessor methods to get and set the current instances.
For example:
bot->SetEnableAvoidance(true); Kaim::ShortcutTrajectoryConfig shortcutConfig; shortcutConfig.SetDefaults(); shortcutConfig.m_maxDistanceFromBot = 20.0f; bot->SetShortcutTrajectoryConfig(shortcutConfig);
The PathFinderConfig class, which you can set up in BotConfig::m_pathFinderConfig or by calling Bot::SetPathFinderConfig(), provides access to some options exposed by the AStarQuery. See AStarQuery Options.
However, the query supports more configuration options than those exposed in the PathFinderConfig. If you want to use any of these other options, or set different options on the fly for a one-off path calculation, you need to set up the query directly. See the "advanced" path calculation method under Getting a Static Path.
If your Bot uses channels and splines to generate its trajectory (see below), you can also use the ChannelComputerConfig class to set up some parameters that govern the characteristics of the channel data generated for each path—for example, the preferred width of the channel. You can set this up in BotConfig::m_channelComputerConfig or by calling Bot::SetChannelComputerConfig()
You can use the PathProgressConfig class to set some parameters that determine how the path following system tracks the progress of the Bot along its path.
For example, if you use the check point system extensively, you may want to customize the PathProgressConfig::m_checkPointRadius value, which determines how close the Bot must come to a check point before it is allowed to continue past the check point. See also Using Check Points.
You can set up the PathProgressConfig in BotConfig::m_pathProgressConfig or by calling Bot::SetPathProgressConfig()
Parameters for controlling the shortcut trajectory system are gathered into the ShortcutTrajectoryConfig class, which you can set up in BotConfig::m_shortcutTrajectoryConfig or by calling Bot::SetShortcutTrajectoryConfig().
For example, you can control how often the Bot checks for a new shortcut, how far away the shortcut can be, the spacing of the candidate points it checks along the path, etc.
Parameters for controlling the channel trajectory system are gathered into the SplineTrajectoryConfig class, which you can set up in BotConfig::m_splineTrajectoryConfig or by calling Bot::SetSplineTrajectoryConfig().
For example, you can control how close the Bot is allowed to come to the channel boundaries on corners, how often it should recompute its spline, the desired length of each spline, etc.
Both trajectory computation systems use parameters from the LocomotionModelConfig class to determine how the final velocity of the Bot should be calculated based on the current target point or the current spline being followed. You can set up this class in BotConfig::m_locomotionModelConfig or by calling Bot::SetLocomotionModelConfig().
The maximum desired speed for the character (LocomotionModelConfig::m_maxDesiredLinearSpeed) is also exposed through shortcuts accessors in the Bot class, Bot::SetMaxDesiredLinearSpeed() and Bot::GetMaxDesiredLinearSpeed()
Both trajectory computation systems skip recomputing the trajectory if the character has not moved more than a minimal distance threshold since the last computation. You can set this threshold in the Bot class using Bot::SetTrajectoryMinimalMoveDistance() and Bot:: GetTrajectoryMinimalMoveDistance().
A NavigationProfile is an object factory that provides instances of classes used during path computations and path following. It has three main purposes:
The World creates and maintains a default NavigationProfile at initialization time, which provides access to instances of all the default path finding and path following classes supplied with the SDK. Every Bot is automatically set up at initialization time to use this default NavigationProfile, unless you specify otherwise.
Note that the default NavigationProfile is fully functional out of the box, and the set of default objects that it serves is highly customizable (see the previous section for details). You can certainly continue to use this default profile for your project. You only need to use a different NavigationProfile if you have a particular need to override the default implementation for one or more of the classes it serves.
The most common needs for user customization in the NavigationProfile include:
In all of these cases, you would need to set up a custom class of NavigationProfile to serve your custom implementation.
NavigationProfiles are managed centrally by the World. Each time you set up a new NavigationProfile, the World assigns it a unique ID. You use this ID value to set up other objects (typically Bots and path finding queries) with the profile they should use.
Note that the unique ID of the default NavigationProfile is always 0.
You can set up a Bot to use your new profile in BotInitConfig::m_startNewPathNavigationProfileId, or by calling Bot::SetNewPathNavigationProfileId(). Any time you request a path calculation by calling Bot::ComputeAStarQueryAsync(), your custom profile will now be used. See also the "basic" path calculation method under Getting a Static Path.
Note, however, that if you set up a Bot with a custom path finding query or your own pre-planned path, as described in the "advanced" path calculation methods on that page, the Bot will automatically use the profile ID set for the query or the Path object while it follows that path. If you want the Bot to use your custom profile, you must also set up your custom query or Path object with the ID of your custom profile by calling its IPathFinderQuery::SetNavigationProfileId() or Path::SetNavigationProfileId() method.
For example:
// The NavigationProfile in this example uses a custom TraverseLogic and a custom IPathEventListObserver. class MyTraverseLogic : public Kaim::DefaultTraverseLogic { public: static KY_INLINE bool CanTraverseNavTriangle(void* userData, const Kaim::NavTriangleRawPtr& triangleRawPtr, const Kaim::NavTag& navTag, KyFloat32* costMultiplier) { ... } }; class MyPathEventListener : public Kaim::IPathEventListObserver { public: virtual void OnPathEventListBuildingStageDone(Kaim::Bot* bot, Kaim::PathEventList& pathEventList, KyUInt32 firstIndexOfNewEvent, FirstIntervalStatus firstIntervalStatus) { ... } virtual void OnPathEventListDestroy(Kaim::Bot* bot, Kaim::PathEventList& pathEventList, DestructionPurpose destructionPurpose) { ... } }; class MyNavigationProfile : public Kaim::NavigationProfile<MyTraverseLogic> { public: virtual Kaim::Ptr<Kaim::IPathEventListObserver> GetSharedPathEventListObserver() { if (m_myPathEventListener == KY_NULL) m_myPathEventListener = *KY_NEW MyPathEventListener(); return m_myPathEventListener; } public: Kaim::Ptr<MyPathEventListener> m_myPathEventListener; }; ... // in your World initialization code: const KyUInt32 databaseCount = 1; m_world = *KY_NEW Kaim::World(databaseCount); Kaim::Ptr<MyNavigationProfile> myNavigationProfile = *KY_NEW MyNavigationProfile(); KyUInt32 navigationProfileId = m_world->AddNavigationProfile(myNavigationProfile); ... // in your Bot initialization code: m_navBot = *KY_NEW Kaim::Bot; Kaim::BotInitConfig botInitConfig; botInitConfig.m_database = m_world->GetDatabase(0); botInitConfig.m_startPosition = m_position; botInitConfig.m_startNewPathNavigationProfileId = navigationProfileId; m_navBot->Init(botInitConfig); // We add the Bot to our Database. m_navBot->AddToDatabase(); ...
At times, you may want to temporarily take complete control over the movement of your character in order to play a particular animation (climbing a ladder, jumping, etc.), in order to play a cutscene, etc.
To take temporary control, you could simply continue your path following as normal, but ignore the velocity computed by the path following system.
However, it is recommended that you temporarily disable path following by calling both Bot::SetDoValidateCheckPoint() and Bot::SetDoComputeTrajectory(). Call them again to re-activate path following when you no longer need total control over the movements of your character. For example:
void MyJumpObject::ManageTraversing() { // Take control m_navBot->SetDoValidateCheckPoint(false); m_navBot->SetDoComputeTrajectory(false); ... // manage playing the jump animation if (animationIsFinished) { // Release control m_navBot->SetDoValidateCheckPoint(true); m_navBot->SetDoComputeTrajectory(true); } }
Note that while the path following system is disabled in this way, your Bot is rendered in blue while visual debugging in the Navigation Lab instead of the default yellow.
Note also that depending on how long you keep control of your character's movement, and how far you drive it, you may need to force the current target point forward along the path when you release control. See also Creating Smart Objects.