[이득우의 언리얼 C++ 게임 개발의 정석] Chapter 12. AI 컨트롤러와 비헤이비어 트리

수민·2023년 4월 18일
0
post-thumbnail

이득우의 언리얼 C++ 게임 개발의 정석을 읽고 개인 공부 목적으로 요약 정리한 글입니다!


👀 NPC AI를 위한 요소

AI 컨트롤러

NPC(Non Player Character) : 플레이어가 조종하지 않지만 레벨에 배치되어 스스로 행동하는 캐릭터
AI 컨트롤러 : 컴퓨터가 AI로 NPC를 제어할 수 있도록 제공해주는 것

Pawn -> 플레이어 컨트롤러에 빙의
Pawn -> AI 컨트롤러에 빙의

NPC이든 플레이어든
캐릭터면 Pawn이 있다.
Pawn은 조종당할 수 있게 설계된 액터 이니깐,,,
플레이어인지 아닌지에 따라 빙의되는 컨트롤러가 다르다.
그래서
빙의된 컨트롤러가 시키는 대로 행동한다.

네비게이션 시스템

NPC는 내가 조종하는게 아니라 스스로 움직여야 한다.
그래서 NPC가 길을 찾도록 하는 장치가 필요하다
그게 바로
네비게이션 메시(Navigation Mesh) 기반의 길찾기 시스템이다.

네비게이션 메시

캐릭터가 갈 수 있는 영역들을 지정해놓은 메시라고 생각하믄 된다.

이 사진에서
초록색으로 표시된 부분이 Navigation Mesh 영역이다.
플레이어가 갈 수 있는 부분!!

관련 함수

Navigation System이 제공하는 함수들
GetRandomPointInNavigableRadius : 이동 가능한 목적지를 랜덤으로 가져오는 함수
SimpleMoveTOLocation : 목적지로 폰을 이동시키는 함수

NavigationSystem 모듈을 추가하고
헤더에 NavigationSystem.h를 선언해야 한다.

NavigationSystemV1 클래스를 사용하면 되고
SimpleMoveToLocatio 함수를 사용하려면 Blueprint/AIBlueprintHelperLibrary.h를 추가하면 된다.

Hunt_Prototype.Build.cs


using UnrealBuildTool;

public class Hunt_Prototype : ModuleRules
{
	public Hunt_Prototype(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "NavigationSystem"});

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

👀 비헤이비어 트리 시스템

비헤이비어 트리 (BehaviorTree)

NPC의 행동 패턴을 체계적으로 설계하기 위한 시스템.
언리얼엔진은 비헤이비어 트리 모델과 이를 편집하는 에디터를 지원한다.

BehaviorTree : NPC가 해야 할 행동을 분석하고 우선순위가 높은 행동부터 실행하도록 트리구조 로 설계하는 기법

필요한 에셋

좌측 : 블랙보드
우측 : 비헤이비어 트리

블랙보드(Blackboard)

인공지능의 판단에 사용하는 데이터 집합.
블랙보드 내 데이터를 기반으로 NPC가 의사결정한다.

비헤이비어 트리(BehaviorTree)

블랙보드 데이터에 기반해 설계한 비헤이비어 트리의 정보를 저장한 에셋
언리얼 에디터에서는 비헤이비어 트리를 시각화해서 저장할 수 있도록 편집 기능을 제공한당.

예시.
관련 설명은 후술하겟슴!!

구성

컴포짓 (Composite)

분기가 실행되는 규칙을 정의하는 노드

  • 셀렉터 (Selector)
    Task들 중 True가 나올 때까지 실행한다.
    자식 노드 중 하나라도 True를 리턴하면 True 리턴

  • 시퀀스 (Sequence)
    연결된 Task들이 False가 될 때까지 왼쪽에서 오른쪽으로 Task를 계속 실행한다.
    모든 자식 노드가 True를 리턴해야 True 리턴

  • 심플 페러렐 (Simple Parallel)
    단순 병렬 노드.
    두 개의 자손만을 가지고
    A를 수행하는 동안 B도 수행하도록 두 개를 동시에 수행하도록 한다.
    ex. 적을 공격하는 동안 적을 향해 회전하기!
    하나는 반드시 단일 Task 노드(Decorator 가능)여야 하고, 하나는 완전한 서브트리여도 된다.
    하나는 주요 Task,
    하나는 부가(필러) Task

태스크 (Task)

AI가 수행할 액션

ExecuteTask 멤버함수를 실행해서 넷 중 하나의 값을 반환해야 한다

  • Aborted : 태스크 실행 중 중단되어 실패
  • Failed : 태스크 수행했지만 실패
  • Succeeded : 태스크 성공적으로 수행
  • InProgress : 태스크 수행중. (실행 결과는 나중에 알려줌)

서비스 (Service)

모든 컴포짓 노드와 연관되는 특수 노드
지정된 시간마다 콜백을 등록하고 주기적으로 발생시켜야 하는 업데이트를 수행한다.

자신이 추가된 컴포짓 노트의 서브트리에 실행이 머물러있는 동안만 활성화된다.

(주로 블랙보드 검사, 업데이트)

데코레이터 (Decorator)

조건문
컴포짓 노드에 Attach해서 블랙보드의 키가 True인지 검증한다.

블랙보드 키값 연결

이렇게 블랙보드에서 키를 생성할 수 있다.

이렇게 비헤이비어 트리 내부에서 블랙보드를 연결하면

블랙보드의 키값을 볼 수 있다.

C++에서 블랙보드 키값 연결

이렇게 AIController에 네임 속성을 제공하자
(static const로 선언해서 키 이름을 초기화했는데, 이렇게 하면 값을 참조하기 편하지만 하드코딩으로 값을 변경해야 하니 주의해야 한다)

값 얻어오기

FVector Origin = OwnerComp.GetBlackboardComponent()->GetValueAsVector(AMyAIController::HomePosKey);

값 설정하기

OwnerComp.GetBlackboardComponent()->SetValueAsVector(AMyAIController::HomePosKey, InPawn->GetActorLocation());
OwnerComp.GetBlackboardComponent()->SetValueAsObject(AMyAIController::TargetKey, MyCharacter);

이후 구현 부분은
책을 보면서 기본 개념을 베이스로 하고 하나씩 하면 어렵지 않다.
지금 코드를 설명하며 포스팅하는건 약간 무의미한 것 같고
몇 주 정도 후에 직접 내가 구현할 때 포스팅하면 좋겠다 !


참고

https://docs.unrealengine.com/5.0/ko/behavior-tree-in-unreal-engine---overview/

https://bbagwang.com/uncategorized/ue4-%EC%97%90%EC%84%9C%EC%9D%98-behavior-tree/

profile
우하하

0개의 댓글