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.
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.
bot->SetEnableAvoidance(true); Kaim::ShortcutTrajectoryConfig shortcutConfig; shortcutConfig.SetDefaults(); shortcutConfig.m_maxDistanceFromBot = 20.0f; bot->SetShortcutTrajectoryConfig(shortcutConfig);
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.
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()
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.
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.
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()
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.
To set up a custom NavigationProfile for a Bot:
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.
// 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.