Make Unreal REAL.
article thumbnail
이득우의 언리얼 C++ 게임 개발의 정석

 

추격 시 플레이어를 저장할 Object 타입의 Target 블랙보드 키를 추가한다.

 

플레이어를 저장할 것이므로 Base Class를 ABCharacter로 지정한다.

  • Class와 Object 타입의 블랙보드 키는 Base Class를 설정할 수 있다.
  • 지정해 주는 것이 좋긴 하지만 어차피 나중에 UObject* 에서 Base Class* 형식으로 캐스팅해 사용해야 하긴 마찬가지다.

 

 

클래스를 선택할 때 파란색으로 표시되는 클래스는 액터 클래스이다.

 

 

ABAIController 클래스에 Target 블랙보드 키의 이름을 저장하는 변수를 선언한다.

 

 

서비스

독립적으로 동작하지 않고 컴포짓에 부착되는 노드다.
컴포짓에 속한 태스크들이 실행되는 동안 반복적인 작업을 실행하는 데 적합하다.

 

서비스를 통해 일정 반경 내의 플레이어를 감지하는 기능을 구현한다.

 

 

새로운 클래스를 생성했으니 CoreMinimal.h를 ArenaBattle.h로 변경한다.

 

 

서비스는 자신이 속한 컴포짓이 활성화 된 경우(하위 태스크들을 실행하는 동안) 설정된 Interval 간격으로 주기적으로 TickNode 함수를 호출한다.

  • ExecuteTask() 함수와 마찬가지로 Node Memory는 객체 혹은 구조체 포인터를 통해 값을 유지해야할 때 사용한다.

 

 

필요한 헤더를 포함한다.

 

 

행동 트리에서 보여질 서비스 이름을 설정하고 실행 주기를 설정한다.

 

 

UWorld->OverlapMultipleByChannel() 함수를 이용해 중심이 Center이고 반지름이 DetectRadius인 구를 생성해 ABCharacter 채널과 겹침을 확인한다.

  • 물리는 월드의 기능이므로 월드에서 함수를 가져온다.
  • Multiple이므로 TArray<FOverlapResult>의 레퍼런스를 전달해야 한다.

 

FCollisionQueryParams의 인자는 (추적 태그, 세밀한 추적 여부, 무시할 액터)이다.

 

DrawDebugSphere() 함수를 이용해 영역을 디버깅한다.

  • 4번째 인자인 Segments는 분절(4일 경우 피라미드 모양) 개수를 뜻한다.

 

 

TickNode() 함수의 나머지 내용이다.

 

감지된 것이 있을 경우 결과를 순회하면서 플레이어가 있는지 확인한다.

  • FOverlapResult.GetActor() 함수로 겹친 액터를 가져올 수 있다.
  • APawn->GetController()->IsPlayerController() 함수로 폰의 컨트롤러가 플레이어 컨트롤러인지 확인할 수 있다.

 

감지된 것 중 플레이어가 있을 경우 Target 블랙보드 키를 플레이어의 ABCharacter로 설정하고 초록색 디버깅 구를 그린다.

 

감지된 것 중 플레이어가 없으면 Target 블랙보드 키를 NULL로 설정하고 오렌지색 디버깅 구를 그린다.

 

감지된 것이 없으면 Target 블랙보드 키를 NULL로 설정하고 빨간색 디버깅 구를 그린다.

 

 

행동 트리로 이동해 조건에 따라 하나의 분기를 선택하는 셀렉터 컴포짓을 추가한다.

  • 같은 조건일 때는 좌측 하위 노드가 우선순위를 갖는다.

 

 

플레이어 추격 시 타게 되는 좌측 분기에서는 Move To 노드의 목적지를 플레이어인 Target으로 설정한다.

  • 블랙보드 키가 Vector3 타입이면 위치로 이동하고 Target이면 알아서 액터를 따라간다.

 

 

추격할지 정찰할지 결정하는 셀렉터 분기에 Detect 서비스를 등록한다.

  • Detect 서비스는 셀렉터의 컴포짓의 하위 노드가 실행되는 동안 실행되므로 이 트리에서는 사실상 매초마다 플레이어를 감지한다.

 

 

이제 Target 블랙보드 키에 따라 분기를 나누면 된다.

 

조건에 따라 분기를 나눌 수 있게 하는 데코레이터(Decorator)를 양쪽 하위 컴포짓에 추가한다.

 

 

좌측 데코레이터는 블랙보드 키 Target이 설정되었을 경우 분기를 타도록 한다.

 

우측 데코레이터는 블랙보드 키 Target이 설정되지 않았을 경우 분기를 타도록 한다.

 

 

양쪽 데코레이터의 Notify Observer를 On Value Change로 변경한다.

  • On Value Change: 블랙보드 키의 값이 바뀌었을 때 Notify 발생
  • On Result Change: 참/거짓 결과가 바뀌었을 때 Notify 방생

 

Observer aborts는 Notify 발생 시 수행할 작업이다.

양쪽 데코레이터 모두 Self인지 확인한다.

  • None: 작업을 중단하지 않고 계속 실행한다.
  • Self: 자신만 중단한다.
    상위 노드가 하위 노드 중 하나의 분기만 선택하는 셀렉터이면 Self로 하면 된다.
  • Lower Priority: 자신까지는 실행하고 우선순위가 낮은 노드(우측 형제들)는 실행하지 않는다.
  • Both: 자신과 형제들을 모두 중단한다.
    상위 노드가 모든 하위 노드를 반복적으로 실행하는 시퀀스이면 Both로 하면 된다.

 

 

반경 600m를 감지 영역으로 플레이어가 감지되면 추격을 시작하고 감지에 실패하면 다시 정찰한다.

 

 

AI가 너무 빠르고 회전이 부자연스럽게 꺾이는 문제가 있어 AI를 위한 새로운 ControlMode를 ABCharacter 클래스에 추가한다.

 

 

컨트롤러에 소유될 때 실행되는 PossessedBy() 함수를 오버라이드하여 구현하도록 한다.

 

 

APawn::IsPlayerControlled() 함수를 통해 폰이 플레이어에 의해 조종당하는 중인지 확인할 수 있다.

 

AI의 속도를 절반으로 줄여 플레이어가 원활하게 추격을 벗어날 수 있도록 한다.

 

 

폰과 Character Movement 컴포넌트가 컨트롤러의 회전을 사용하지 않고 움직이는 방향으로 회전하도록 한다.

 

 

행동 트리에서 서비스, 셀렉터와 블랙보드를 활용해 추격 기능을 구현하는 데 성공했다.

 

profile

Make Unreal REAL.

@diesuki4

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그