Gameware Navigation은 메모리로 로드한 NavData에서 사용할 고성능 런타임 쿼리 세트를 제공합니다. 이러한 쿼리를 사용하면 지세 및 캐릭터의 이동 기회에 대해 인식할 수 있는 광범위한 질문에 대답할 수 있습니다. 그 예는 다음과 같습니다.
각 유형의 쿼리는 자체 클래스에서 캡슐화됩니다. 전체 목록은 IQuery 클래스를 구현하는 클래스를 참조하십시오. 입력 및 출력을 포함하여 각 쿼리 유형에 대한 전체 설명은 해당 클래스 설명을 참조하십시오.
각 쿼리는 현재 단일 Database로 로드된 전체 NavData 세트를 고려합니다. 다른 Databases에 대해 병렬로 쿼리 사본을 여러 개 실행할 수 있지만 단일 쿼리는 여러 Databases에 대해 동시에 만들어질 수 없으며, 쿼리 또한 Database로 로드된 섹터의 하위 세트로 제한될 수 없습니다.
모든 쿼리에는 일부 작업 메모리(임시 데이터를 저장하기 위해 계산 중에 사용하는 버퍼)가 필요합니다. 예를 들어 AStarQuery는 NavData에서 경로를 찾을 때 탐색하는 후보 노드 목록을 저장하기 위해 해당 작업 메모리를 사용해야 합니다.
쿼리를 처리할 때마다 계산 중에 해당 쿼리가 사용할 WorkingMemory 클래스의 인스턴스를 제공할 수 있습니다. 제공하지 않는 경우 쿼리가 탐색하도록 구성된 Database에 의해 유지되는 공유 버퍼를 쿼리에서 사용합니다.
두 모드 중 하나에서 만든 각 쿼리를 실행할 수 있습니다.
게임 루프 밖에서(예: 데이터 생성 프로세스의 사후 처리 단계) 쿼리를 시작하려는 경우 차단 메서드를 사용해야 합니다.
이 호출에서는 다른 모든 구성 매개변수의 값을 재설정하지 않으므로 새 입력 데이터로 쿼리를 초기화할 때마다 재설정하지 않고 동일한 쿼리를 여러 번 실행하는 동안 동일한 구성 값을 다시 사용할 수 있습니다.
예를 들어 다음 코드는 RayCastQuery를 설정합니다.
Kaim::RayCastQuery<Kaim::DefaultTraverseLogic> rayCastQuery; rayCastQuery.BindToDatabase(m_world->GetDatabase(0)); // Optional configuration ... rayCastQuery.SetDynamicOutputMode(Kaim::QUERY_SAVE_TRIANGLES); rayCastQuery.Initialize(start, move2D);
동일한 Database에 대해 동일한 구성을 사용하여 쿼리를 재실행하려면 Initialize()를 호출하여 새 입력 값을 제공하면 됩니다.
여러 유형의 쿼리가 탐색하는 NavData와 관련된 사용자 정의 NavTag를 고려할 수 있습니다. 이러한 쿼리는 모두 템플릿 인수로 술어를 허용합니다. NavTag 간의 전환을 탐지하는 경우 쿼리가 이 술어에서 클래스 메서드를 호출하여 새 NavTag 금지 여부, 전환을 교차할 수 있는지 여부를 결정합니다.
이 술어는 PathFollower 클래스에서 허용된 것과 동일하며 AStarQuery에서 사용된 사용자 정의자와 동일한 메서드를 대부분 사용합니다. 술어 클래스에서 구현해야 하는 인터페이스에 대한 요구 사항에 대한 자세한 내용은 NavTag 금지, 회피 및 선호을(를) 참조하십시오.
NavTag 설정에 대한 자세한 내용 사용자 정의 데이터로 태그 지정을(를) 참조하십시오.
즉시 또는 비동기적으로 실행하는지에 따라 쿼리를 다르게 시작합니다.
즉시 모드에서 쿼리를 시작하려면 PerformQueryBlocking() 메서드를 호출합니다.
rayCastQuery.PerformQueryBlocking();
World의 업데이트가 진행되는 동안 쿼리를 시작하지 않는 한 스레드에서 즉시 쿼리를 시작하는 것이 안전합니다.
World를 다음에 업데이트하는 동안 비동기적으로 쿼리를 시작하려면 World::PushAsyncQuery() 메서드를 호출하고 쿼리 오브젝트를 전달합니다. World는 대기열에 쿼리를 배치하고 예정된 CPU 시간이 허용하는 즉시 쿼리를 수행합니다.
m_world->PushAsyncQuery(&rayCastQuery);
자체적으로 예정된 CPU 시간에서 자체 QueryQueue 오브젝트를 설정하고 쿼리의 처리를 관리할 수 있습니다. QueryQueue를 처리할 때 예정된 CPU 시간이 소모되기 전까지 순서대로 대기열의 앞에서 쿼리를 수행합니다. 그런 다음 다시 처리할 때까지 계산을 일시 중지합니다(일반적으로 다음 프레임까지).
자세한 내용은 QueryQueue 클래스를 참조하십시오.
World의 업데이트가 진행되는 동안 쿼리를 처리하지 않는 한, 즉시 모드에서 쿼리를 실행하는 것과 같이 스레드에서 QueryQueues를 처리하는 것이 안전합니다.
그러나 비동기 모드에서 쿼리 실행과 같이 현재 프레임에서 대기열이 처리를 완료한 직후 각 쿼리의 결과를 사용할 수 있도록 보장하지 않습니다.
언제든지 GetResult() 메서드를 호출하여 쿼리의 현재 결과를 검색할 수 있습니다.
모든 쿼리는 쿼리 클래스별 열거를 사용하여 처리 상태 및 결과를 나타냅니다. 이 열거는 쿼리 클래스와 동일한 이름을 가지며 접미사로 Result가 붙습니다. 예를 들어 RayCastQuery는 RayCastQueryResult를 생성합니다.
비동기적으로 쿼리를 시작하는 경우 결과 코드를 사용하여 쿼리가 성공적으로 처리를 완료했는지 여부를 확인할 수 있습니다. 일반적으로 DONE을 포함하는 열거 값은 쿼리에서 계산이 완료되었다는 것입니다. 예를 들어 처리가 완료될 때까지 RayCastQuery는 RAYCAST_NOT_INITIALIZED 또는 RAYCAST_NOT_PROCESSED를 반환하고 그런 다음 RAYCAST_DONE_START_OUTSIDE, RAYCAST_DONE_ARRIVALPOS_FOUND_MAXDIST_REACHED, RAYCAST_DONE_LACK_OF_WORKING_MEMORY 등을 반환할 수 있습니다.
쿼리 유형 및 처리 결과에 따라 쿼리의 다른 데이터 구성원에서 추가 출력을 검색할 수도 있습니다. 아래를 참조하십시오.
NavMesh를 통해 전파한 일부 쿼리 유형은 교차하는 데이터를 저장할 수 있습니다. 예를 들어 쿼리는 전파하는 동안 교차하는 삼각형 목록 또는 다른 NavTag를 교차하는 하위 세그먼트 목록을 저장할 수 있습니다. 쿼리 후 교차된 데이터 목록을 검색하고 쿼리에서 교차된 지세의 속성을 검색할 수 있습니다. 예를 들어 캐릭터는 고도 등의 변화, 삼각형과 관련된 NavTag를 기반으로 결정을 내릴 수 있습니다.
이러한 쿼리에는 모두 SetDynamicOutputMode() 메서드가 들어 있으며, 기록해야 하는 출력 데이터 유형을 쿼리에게 알려 주려면 이를 호출해야 합니다. 기본적으로 교차된 데이터는 기록되지 않으므로 SetDynamicOutputMode()를 호출하고 DynamicOutputMode 열거에서 원하는 값을 전달하여 명시적으로 쿼리가 기록하도록 지시해야 합니다.
GetQueryDynamicOutput() 메서드를 호출하여 교차된 데이터를 검색할 수 있습니다. 이렇게 하면 QueryDynamicOutput 오브젝트에 대한 포인터를 반환하며 해당 메서드는 저장된 데이터에 대한 액세스 권한을 제공합니다. 필요한 경우 게임의 좌표계로 출력 데이터를 다시 변환해야 합니다.
예를 들어 다음 코드는 교차하는 NavMesh 삼각형을 검색하도록 RayCastQuery를 설정하는 방법을 보여줍니다.
Kaim::RayCastQuery<Kaim::DefaultTraverseLogic> rayCastQuery; rayCastQuery.BindToDatabase(m_world->GetDatabase(0)); ... // enable saving triangles rayCastQuery.SetDynamicOutputMode(Kaim::QUERY_SAVE_TRIANGLES); rayCastQuery.Initialize(start, dir2D, maxdist); rayCastQuery.PerformQueryBlocking(); // retrieve data Kaim::QueryDynamicOutput* qoutput = rayCastQuery.GetQueryDynamicOutput(); // iterate through the list of triangles KyUInt32 numberOfTriangles = qoutput->GetNavTrianglePtrCount(); for (KyUInt32 i_triangle = 0; i_triangle < numberOfTriangles; i_triangle++) { const Kaim::NavTrianglePtr thisTriangle = qoutput->GetNavTrianglePtr(i_triangle); // handle the triangle here. }
각 프레임에서 해당 SendVisualDebug() 메서드를 호출하여 모든 쿼리에 대한 시각적 디버깅 데이터를 렌더링할 수 있습니다. Navigation Lab이 게임에 연결되어 있는 동안 쿼리가 자동으로 표시 목록을 구성하고 이를 Navigation Lab에 전송합니다.
표시 목록의 내용 및 그에 따라 Navigation Lab에 표시되는 데이터는 쿼리 유형에 따라 다릅니다. 쿼리에 표시된 시각적 데이터의 중요성을 해석하려면 sdk₩include₩gwnavruntime₩queries₩blobs 디렉토리의 QueryDisplayListBuilder 클래스에 있는 인라인 구현을 참조하십시오.
비동기적으로 쿼리를 수행하거나 쿼리를 처리하기 위해 대기열에 배치하는 경우 현재 처리 상태를 확인하기 위해 쿼리 결과를 폴링하지 않고 쿼리가 완료될 때 알림을 받는 것이 유용할 수 있습니다.
실행하기 위해 쿼리를 World로 미는 경우 쿼리가 처리된 후 World를 업데이트하는 동안 오브젝트의 IOnDone::OnDone() 메서드가 자동으로 호출됩니다. 자체 QueryQueue를 사용하는 경우 해당 쿼리가 처리된 후 다음에 QueryQueue::FlushQueries()를 호출할 때 오브젝트가 호출됩니다.
해당 IOnDone::OnDone() 메서드가 호출된 후 쿼리 클래스의 m_onDone 구성원이 KY_NULL로 다시 설정됩니다. 동일한 쿼리 인스턴스를 다시 시작하고 알림을 다시 받으려는 경우 m_onDone 구성원을 다시 설정해야 합니다.
Gameware Navigation API의 여러 쿼리도 Navigation Lab에 제공되어 쿼리를 실행하고 쿼리 결과에서 시각적 피드백을 제공합니다. 이는 지세에 생성된 NavData 테스트 및 각 쿼리의 다른 입력 및 출력 값을 파악하는 데 유용할 수 있습니다.
Navigation Lab에서 쿼리 실행에 대한 소개는 Navigation Lab 시작하기을(를) 참조하십시오.