BulletAnt 개발일지 (13) - optional, Dynamic NavMesh

김펭귄·5일 전

Today What I Learned (TIL)

목록 보기
128/139

코어 좌표 방어 코드

원래 코어가 부숴지면 게임을 바로 끝내는것이 시나리오였으나, QA를 위해 코어가 없어도 게임이 계속 진행될 수 있도록 해달라는 요청이 들어왔다.

하지만 적들이 스폰될 때 코어를 타겟삼아 해당좌표로 이동하였고, 코어가 없다면 이 좌표를 어떻게 설정해야할지 고민되었다.

// BaseEnemyCharacter.cpp
void ABaseEnemyCharacter::InitTarget()
{
	TargetActor = BAGameState->GetTargetCore();
}

// MoveToLoc.cpp
void UMoveToLoc::StartMoveToTarget()
{
	Result = CachedAIController->MoveToLocation(Target->GetAnchor(), AcceptanceRadius);
}

좌표는 FVector이기 때문에 매직넘버를 사용해 예외처리를 하기보단, optional을 사용해보기로 하였다.

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 갱신 문제

현재 구조에서는 게임 도중 포탑을 설치해도 NavMesh가 갱신되지 않았다.

그 결과 적들은:

  • 새 장애물을 인식하지 못하고
  • 기존 최단 경로 기준으로
  • 코어 방향으로 직선 이동

을 시도했다.

문제는 실제로는 포탑으로 길이 막혀있기 때문에 좁은 틈으로 진입하려다 실패하고, 제자리 이동만 반복하는 현상이 발생했다.

영상에서도 보면:

  • 코어 근처에 빨간 점이 계속 새로 찍히는데
  • 이는 MoveToLocation 실패 후 재시도 지점이었다.

Dynamic NavMesh

문제 해결을 위해서는 NavMesh 자체를 갱신해야 했다.
갱신방법으로는 NavModifierVolume, Navigation Invoker 중에서 고민을 하였다.

특히 NavModifier 방식은 필요한 영역만 갱신 가능하고, 성능 부담도 적어서 더 적합한 구조였다.
다만 이는 건물 액터에 Modifier를 추가해야해서, 우선은 Dynamic으로 변경했다.

인게임 중 배치되는 모든 오브젝트에 대해 NavMesh를 실시간 재계산하도록 만든 것이다.
물론 성능 부담이 크다는 단점이 있다.

실제로 테스트해보니:

  • 포탑을 하나씩 설치할 때마다
  • NavMesh가 정상적으로 갱신되고
  • 적 이동 경로도 끊기는 것

을 확인할 수 있었다.

profile
반갑습니다

0개의 댓글