캐릭터의 경로 따르기 시스템을 사용자 정의하는 방법에는 클래스 메서드 호출과 같은 간단한 방법부터 핵심 클래스 재구현과 같은 복잡한 방법까지 여러 가지가 있습니다. 이 항목과 이 섹션의 나머지 항목에서는 경로 따르기 시스템의 여러 요소의 작동을 제어하는 가장 일반적인 옵션 및 전략 중 몇 가지를 간략하게 설명합니다.
각 봇은 경로를 찾고 따르는 방법을 제어하는 광범위한 구성 매개변수를 수용합니다.
Bot 구성 매개변수는 BotConfig 오브젝트에서 설정할 수 있으며, 초기화 시 Bot::Init()를 호출하여 제공합니다. 이 방법을 사용하면 단일 구성 오브젝트를 만들고 설정할 수 있으며, 이 오브젝트를 사용하여 동일한 구성 매개변수 세트로 이루어진 여러 게임 캐릭터를 설정할 수 있습니다.
BotConfig 클래스는 몇 가지 단순 데이터 구성원을 포함하며 다른 매개변수를 기능 범주에 따라 하위 구성 오브젝트로 그룹화합니다.
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);
BotConfig의 모든 구성 매개변수는 Bot API의 메서드를 호출하여 각 캐릭터에 대해 동적으로 설정할 수도 있습니다.
BotConfig의 단순 데이터 구성원은 Bot 클래스의 메서드를 통해 직접 노출됩니다. 또한 Bot 클래스는 BotConfig에 의해 노출된 하위 구성 오브젝트에 대해 데이터 액세서 메서드를 노출하여 현재 인스턴스를 가져오고 설정합니다.
bot->SetEnableAvoidance(true); Kaim::ShortcutTrajectoryConfig shortcutConfig; shortcutConfig.SetDefaults(); shortcutConfig.m_maxDistanceFromBot = 20.0f; bot->SetShortcutTrajectoryConfig(shortcutConfig);
그러나 쿼리는 PathFinderConfig에 노출된 옵션보다 더 많은 구성 옵션을 지원합니다. 이러한 다른 옵션을 사용하거나 일회성 경로 계산을 위해 즉시 다른 옵션을 설정하려면 쿼리를 직접 설정해야 합니다. 정적 경로 가져오기에서 "고급" 경로 계산 방법을 참조하십시오.
PathProgressConfig 클래스를 사용하면 경로 따르기 시스템이 경로를 따라 이동하는 Bot의 진행률을 추적하는 방법을 결정하는 일부 매개변수를 설정할 수 있습니다.
예를 들어 체크 포인트 시스템을 광범위하게 사용하는 경우 PathProgressConfig::m_checkPointRadius 값을 사용자 정의하여 Bot이 체크 포인트에 얼마나 가깝게 접근해야 해당 체크 포인트를 지나서 계속 갈 수 있는지를 결정할 수 있습니다. (체크 포인트 사용 참조).
PathProgressConfig는 BotConfig::m_pathProgressConfig에서 설정하거나 Bot::SetPathProgressConfig()를 호출하여 설정할 수 있습니다.
예를 들어 Bot이 새 바로 가기를 확인하는 빈도, 바로 가기를 얼마나 멀리 배치할 수 있는지 정도, 경로를 따라 확인되는 후보 포인트의 간격 등을 제어할 수 있습니다.
예를 들어 Bot이 모서리의 채널 경계에 얼마나 가깝게 다가갈 수 있는지 정도, 해당 스플라인을 다시 계산해야 하는 빈도, 각 스플라인의 원하는 길이 등을 제어할 수 있습니다.
또한 캐릭터에 원하는 최대 속도(LocomotionModelConfig::m_maxDesiredLinearSpeed)는 바로 가기 액세서를 통해 Bot 클래스, Bot::SetMaxDesiredLinearSpeed() 및 Bot::GetMaxDesiredLinearSpeed()에 노출됩니다.
NavigationProfile은 경로 계산 및 경로 따르기 중 사용되는 클래스의 인스턴스를 제공하는 오브젝트 공장이며, 다음과 같은 세 가지 주요 용도로 사용됩니다.
World는 초기화 시에 기본 NavigationProfile을 만들고 유지하여 SDK와 함께 제공된 모든 기본 경로 찾기 및 경로 따르기 클래스의 인스턴스에 대한 액세스 권한을 제공합니다. 다르게 지정하지 않는 한 모든 Bot은 초기화 시에 이 기본 NavigationProfile을 사용하도록 자동 설정됩니다.
기본 NavigationProfile은 바로 사용할 수 있는 모든 기능을 제공하며 NavigationProfile에서 제공하는 기본 오브젝트 세트는 원하는 대로 사용자 정의할 수 있습니다(자세한 내용은 이전 섹션 참조). 이 기본 프로필은 모든 프로젝트에 계속 사용할 수 있습니다. 이 프로필이 제공하는 하나 이상의 클래스에 대한 기본 구현을 특별히 재정의해야 하는 경우에만 다른 NavigationProfile을 사용해야 합니다.
NavigationProfile을 사용자 정의하는 가장 일반적인 경우는 다음과 같습니다.
이러한 모든 경우에 NavigationProfile의 사용자 정의 클래스를 설정하여 사용자 정의 구현을 제공해야 합니다.
NavigationProfile은 중앙에서 World에 의해 관리됩니다. 새 NavigationProfile을 설정할 때마다 World에서 고유 ID를 할당합니다. 이 ID 값을 사용하여 다른 오브젝트(일반적으로 Bot 및 경로 찾기 쿼리)를 해당 오브젝트가 사용해야 하는 프로필로 설정합니다.
기본 NavigationProfile의 고유 ID는 항상 0입니다.
Bot에 대해 사용자 정의 NavigationProfile을 설정하려면
그러나 해당 페이지의 "고급" 경로 계산 방법에 설명된 대로 사용자 정의 경로 찾기 쿼리 또는 사용자 고유의 사전 계획된 경로를 사용하여 Bot을 설정하는 경우 Bot은 해당 경로를 따르는 동안 쿼리 또는 Path 오브젝트에 대해 설정된 프로필 ID를 자동으로 사용합니다. Bot이 사용자 정의 프로필을 사용하도록 하려면 IPathFinderQuery::SetNavigationProfileId() 또는 Path::SetNavigationProfileId() 메서드를 호출하여 사용자 정의 쿼리 또는 Path 오브젝트도 사용자 정의 프로필의 ID로 설정해야 합니다.
// 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();
...
경우에 따라, 특정 애니메이션(사다리 오르기, 점프 등)이나 컷신(cutscene) 등을 재생하기 위해 캐릭터의 이동을 일시적으로 완전히 제어할 수 있습니다.
일시적으로 제어하기 위해 정상적으로 경로 따르기를 계속하되, 경로 따르기 시스템에 의해 계산된 속도를 무시할 수 있습니다.
그러나 Bot::SetDoComputeTargetOnPath()와 Bot::SetDoComputeTrajectory()를 모두 호출하여 경로 따르기를 일시적으로 비활성화하는 것이 좋습니다. 캐릭터의 이동을 더 이상 완전히 제어할 필요가 없는 경우 이 두 메서드를 다시 호출하여 경로 따르기를 다시 활성화할 수 있습니다. 예를 들면 다음과 같습니다.
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);
}
}경로 따르기 시스템이 이런 식으로 비활성화된 동안 Bot은 Navigation Lab에서 시각적으로 디버깅되면서 기본 노란색 대신 파란색으로 렌더링됩니다.
또한 캐릭터의 이동을 제어한 기간 및 캐릭터를 이동한 거리에 따라 제어를 해제할 때 현재 대상 점을 경로에서 앞으로 강제 이동해야 할 수도 있습니다 (스마트 오브젝트 만들기 참조).