최종 프로젝트 - 핵심기술(3D 수중 AI)

정혜창·2025년 6월 27일

내일배움캠프

목록 보기
59/64

📌 개요

프로젝트에서 2개월간 수중 환경 전용 AI 시스템을 설계 및 구현.

기존 지상 네비게이션 한계를 극복하고, 3D 공간에서 자연스럽게 움직이며 플레이어와 상호작용하는 적 AI를 개발.


📌 몬스터 파이프라인

1️⃣ 파이프라인

  • 환경 입력
    • AI는 기본적으로 Player의 위치, 조명, 장애물에 반응하여 작동.
  • AI 감지
    • Player는 Perception 감지 시스템 UAISenseConfig_Sight 을 통하여 감지
    • 조명은 Player의 캐릭터 AUnderwaterCharacter 의 LanternComponent를 통하여 조명 감지
    • 작살에 의해 피해를 입었을 때 Player를 감지할 수 있도록 로직 설계
    • Custom 3D EQS Generator를 직접 구현하여 Pathfinding Test를 통해 장애물 감지
  • 어그로 관리
    • Player를 감지하는 시스템이 시각 Perception, 조명, 피격 3가지
    • 멀티 플레이어 환경에서 여러 Player와 3가지 감지 시스템으로 인하여 복잡한 어그로 관리가 필요
    • TMap<AActor*, int32> DetectionRefCounts 를 통해 어그로 관리를 유연하게 처리
  • Blackboard / 상태 갱신
    • 서술한 피격 시스템에 의해 Monster의 상태를 갱신하고 Blackboard의 TargetActor, FleeLocation, InvestigateLocation, MonsterState 등 여러 Key에 값을 할당
  • BehaviorTree / 행동트리
    • Blackboard의 KeyValue를 바탕으로 AI의 행동트리 결정, 실행
  • 애니메이션 / FX
    • MonsterState (몬스터 상태)를 바탕으로 해당 Montage, VFX, SFX 재생

2️⃣ UML


📌 3D AI 움직임을 위한 기술

1️⃣ 3D Navmesh Plugin

기존 언리얼의 Navmesh는 Z축의 높낮이는 고려하지 않는 XY평면 2D 기반으로 설계되어 있음. 따라서 Unreal의 Pathfinding System 또한 2D 기반으로 설계 되어 있다.

그래서 3D 상의 AI움직임을 위해서 직접 3D Pathfinding 알고리즘을 구현하여 AI Actor를 SetActorLocation을 하는 방법, 또는 Navmesh를 3차원상에 투영할 수 있도록 하는 것 방법이 필요하였음.

시간 내에 더 리얼한 AI의 움직임을 위해서 Navmesh를 3차원상에 투영할 수 있는 FlyingAgent Navigation시스템을 사용 (유료 plugin)

NavMesh를 설치하였을 때 생성되는 FlyingNavigationData-FlyingAgent

플러그인 적용 뒤, Navmesh를 설치하고 Build 했을 때 3차원 AI 이동 가능 영역이 계산된 모습

2️⃣ Custom 3D EQS Generator

언리얼 기본 EQS 제너레이터는 2D(Grid/Simple Grid/Donut 등) 기반이라, 3D 환경(수중) 에서 AI 위치 탐색에 한계가 있음

👉 3차원 공간 전체에서 후보 지점을 자동 생성하고, 네비게이션 가능 영역만 필터링할 수 있는 EQS 제너레이터가 필요

  • 클래스: UEQG_XYZGrid
  • 핵심 구현:
    • 쿼리 기준 위치(예: 플레이어/타겟/쿼리러) 기준
    • XY 평면 + Z축(높이) 방향으로 → GridHalfSizeXY, GridHalfHeightZ, PointSpacing 설정값 활용
    • 지정된 3D 박스 영역에 입체적으로 후보 점 생성
    • 각 후보 점마다 NavMesh Projection NavigationSystemV1::ProjectPointToNavigation → 이동 가능한 위치만 필터링 및 등록

3D EQS Generate, (Test : Distance, Pathfinding) 적용 후 TestPawn에 적용한 모습

3D EQS를 적용한 뒤 AI가 해당 WinnerPoint로 이동하는 모습


📌 DotProduct를 활용한 조명 노출에 반응하는 AI

목표 : 3D DotProduct 계산을 통해 플레이어의 조명 방향과 몬스터 위치를 실시간으로 비교, 조명 콘에 노출된 시간을 누적 감지하여, AI 몬스터가 Patrol - Investigate - Chase 등 다양한 상태로 동적으로 전환하는 시스템 구현

기술 포인트:

  • 조명 Forward 벡터와 몬스터 위치 벡터의 DotProduct로 실시간 노출 각도 체크
  • 일정 각도 내, 일정 시간 이상 노출 시 상태 자동 전환
  • 각 상태마다 EQS, 네비메시, 사운드, 애니메이션 등과 연동
  • AI Perception 한계를 직접 보완, 플레이어 전략에 따라 실시간으로 변화하는 AI 행동 구현

효과:

플레이어의 조명 사용법에 따라 AI가 다양한 방식으로 반응,

몰입감 및 긴장감 대폭 상승.

기존 AI 센싱 시스템 대비 “실제 플레이 환경/의도”를 더 정밀하게 인식하여

다이나믹하고 예측 불가능한 게임플레이 연출 가능.

1️⃣ DotProduct를 활용한 광원 노출 감지

  • 조명 방향(플레이어의 라이트 Forward 벡터)과 몬스터-조명 벡터(조명 → 몬스터) → 두 벡터의 DotProduct 계산을 통해 → 몬스터가 조명 콘(cone) 안에 실제로 있는지, 노출 각도가 어느 정도인지 실시간 체크
FVector DirectionToMonster = TargetActor->GetActorLocation() - ConeOrigin;
    const float DistanceToMonster = DirectionToMonster.Size();
    DirectionToMonster.Normalize();
    
    float DotProduct = FVector::DotProduct(ConeDirection, DirectionToMonster);
    float AngleToMonster = FMath::RadiansToDegrees(FMath::Acos(DotProduct));
    if (AngleToMonster > ConeAngle || DistanceToMonster > ConeHeight)
    {
    	// 몬스터가 라이트의 범위 밖에 있거나, 라이트의 각도 범위를 벗어남
    	return false;
    }
    
  • 노출 시간 누적:
    • 조명에 노출된 시간(ExposureTime)을 실시간 누적/초기화
    • 일정 시간 이상 노출되면 상태 전환

2️⃣ 노출 시간에 따라 AI 상태 전환 로직과 적용

  • 상태(Enum)
    • Patrol: 평상시 순찰
    • Investigate: 짧게 조명 노출 시, 플레이어가 있었던 위치로 조사
    • Chase: 일정 시간 이상 지속 노출 시, 플레이어 추격
    • Flee/Attack 등 추가 가능
      • Flee 는 HorrorCreatrue만의 특별한 상태. Player을 삼킨 채로 도망.
  • 전환 흐름
    • 조명에 짧게 노출:
      • ExposureTime < 임계값 → Patrol → Investigate로 전환
    • 지속 노출:
      • ExposureTime ≥ 임계값 → Investigate/Patrol → Chase로 전환
    • 조명 밖:
      • ExposureTime 리셋, 일정 시간 후 Patrol로 복귀
  • 상태 전환 시 행동 변화
    • Investigate: 마지막 노출 위치로 이동(3D EQS 연동)
    • Chase: 플레이어 추격 (Navmesh 기반 이동)
    • Patrol: 3D EQS 를 통해 적절한 랜덤 위치로 이동

조명에 반응 하는 AI


📌 멀티플레이 / 네트워크 연동 AI

  • AI의 행동(상태, 감지, 위치)이 여러 플레이어에게 똑같이, 실시간으로 보이도록 AI의 상태 전환(조사/추격/도주)이 모든 클라이언트에 동기화

1️⃣ 서버-클라이언트 아키텍처

  • 서버 권한(Authority) 기반:
    • AI의 상태 변화(조명 노출 감지, 상태 전환 등)는 항상 서버에서 결정
    • 클라이언트는 "명령/요청"만 보낼 수 있고, 최종 상태 변화/위치/애니메이션/사운드 재생 등은 서버→클라로 복제(Replication)
  • 멀티플레이/네트워크 연동
    • AI 상태, 감지/추적 정보의 서버-클라이언트 동기화
  • 애니메이션 및 사운드 연동
    • 이동/추적/공격 등 상황별 AI 몽타주 및 루프 사운드 동기화 (NetMulticast)

📌 상태에 따른 애니메이션, FX 구현

몬스터의 모든 오디오 효과를 일원화·유연하게 관리하기 위해 MonsterSoundComponent를 직접 설계.

Loop 사운드(순찰/추격/도주 등)는 MonsterSoundComponent 내에서 각각의 AudioComponent로 통합 관리하며, 공격·피격·조명반응 등 단발성 사운드는 AnimNotify와 연동하여 상황에 따라 즉각적으로 재생.

단조로운 공격 연출을 탈피하기 위해 TArray로 다양한 공격 애니메이션을 관리하고, 공격 시마다 랜덤하게 몽타주를 선택·재생하여 더욱 다채로운 AI 행동과 사운드 연동이 이루어지도록 구현.

1️⃣ 구현 포인트

  • MonsterSoundComponent 기반 루프 사운드 관리
    • Patrol/Chase/Flee 루프 사운드를 개별 AudioComponent로 분리 관리
    • 몬스터 상태(State) 전이에 따라 루프 사운드 자동 전환 및 페이드 인/아웃
  • 단발성 사운드(공격/피격/특수) AnimNotify 연동
    • AnimNotify를 통한 타이밍 정확한 단발성 SFX 동기화
    • 루프 사운드 재생 중 액션 SFX 발생 시 Duck(볼륨 감소) & Recover(복구) 처리
  • 공격 애니메이션 랜덤화
    • TArray<UAnimMontage*>에 여러 공격 몽타주를 저장
    • 공격 시마다 FMath::RandRange를 이용해 랜덤 선택·재생하여 단조로움 최소화
    • 각 공격 몽타주마다 개별 AnimNotify로 SFX 자동 연동

업로드중..

profile
Unreal 1기

0개의 댓글