원래 코어가 부숴지면 게임을 바로 끝내는것이 시나리오였으나, QA를 위해 코어가 없어도 게임이 계속 진행될 수 있도록 해달라는 요청이 들어왔다.
하지만 적들이 스폰될 때 코어를 타겟삼아 해당좌표로 이동하였고, 코어가 없다면 이 좌표를 어떻게 설정해야할지 고민되었다.
// BaseEnemyCharacter.cpp
void ABaseEnemyCharacter::InitTarget()
{
TargetActor = BAGameState->GetTargetCore();
}
// MoveToLoc.cpp
void UMoveToLoc::StartMoveToTarget()
{
Result = CachedAIController->MoveToLocation(Target->GetAnchor(), AcceptanceRadius);
}
좌표는 FVector이기 때문에 매직넘버를 사용해 예외처리를 하기보단, optional을 사용해보기로 하였다.
std::optional은 값이 있을 수도, 없을 수도 있는 상태를 표현하는 C++17 타입이다.
기존의:
int GetID()
{
return -1;
}
같은 매직 넘버 방식보다 명확하고 안전하다.
#include <optional>
std::optional<int> Value;
Value = 10; // 값 저장
if (Value) // 값 들어있는지 확인
{
}
// 값 접근
*Value;
Value.value();
// 값 제거
Value.reset();
std::nullopt // 값 없음
FVector UMoveToLoc::GetProjectedTargetLoc()
{
std::optional<FVector> CoreLocation;
if (Target->IsA(ABaseCore::StaticClass()))
{
CoreLocation = GetAnchor();
}
if (CoreLocation.has_value())
{
TargetLocation = *CoreLocation;
}
else
{
TargetLocation = GetClosestLocation();
}
// ... //
}
현재 구조에서는 게임 도중 포탑을 설치해도 NavMesh가 갱신되지 않았다.

그 결과 적들은:
을 시도했다.
문제는 실제로는 포탑으로 길이 막혀있기 때문에 좁은 틈으로 진입하려다 실패하고, 제자리 이동만 반복하는 현상이 발생했다.
영상에서도 보면:
MoveToLocation 실패 후 재시도 지점이었다.문제 해결을 위해서는 NavMesh 자체를 갱신해야 했다.
갱신방법으로는 NavModifierVolume, Navigation Invoker 중에서 고민을 하였다.
특히 NavModifier 방식은 필요한 영역만 갱신 가능하고, 성능 부담도 적어서 더 적합한 구조였다.
다만 이는 건물 액터에 Modifier를 추가해야해서, 우선은 Dynamic으로 변경했다.

인게임 중 배치되는 모든 오브젝트에 대해 NavMesh를 실시간 재계산하도록 만든 것이다.
물론 성능 부담이 크다는 단점이 있다.
실제로 테스트해보니:
을 확인할 수 있었다.
