[예제로 배우는 UE4] AI, Behavior Tree(인공지능, 비헤이비어 트리)
.
언리얼 엔진 AI 제작 관련 챕터 따라만들어보고 메모한 내용 옮겨봅니다. 언리얼 엔진에서 제공하는 비헤이비어 트리와 블랙보드를 활용한 AI 제작을 진행해보고 그 개념과 사용법을 익혀봅니다.
- UE와 C++를 사용한 1인칭 게임 만들기
- 발사체 및 발사체 이동 컴포넌트 작업하기
- UE4 AI 툴셋 구성(블랙보드, 비헤이비어 트리, AI 컨트롤러)
- 애니메이션 에셋과 C++ 오브젝트 간의 통신
- NavMesh와 NavAgent 속성과 같은 길 찾기 오브젝트 구성
- 블루프린트와 C++에서 사용하는 커스텀 AI 에셋 생성하기
- UE4의 커스텀 콜리전 채널 만들고 작업하기
프로젝트 설정
NewProject > C++ > Basic Code
Project Name : BossMode
1인칭 캐릭터
Temp Project 만들어서 에셋 이주시켜야 함.
Blueprint > First Person 프로젝트, 이름은 Temp 로 제작.
콘텐츠 브라우저의Content>FirstPerson 폴더 통째로 이전.
FPC 시작 (First Person Character)
C++ 위저드 > character 클래스 상속 > BMCharacter 클래스 생성.
FPS 조준/이동 만들기
코드작성.
BMAIController.h/cpp
Possess() 함수 override 가 final 키워드로 컴파일 에러.
최신버전에서는 OnPossess() 로 override.
여기서 BlackboardComp 초기화,
BehaviorTreeComponent 를 시작
이부분이 중요.
BossMode 프로젝트 생성.
FirstPerson 블루프린트 프로젝트에서 어셋 Imigrate
BMCharacter 클래스 생성. 폰 메시(팔), 총 메시, 카메라 컴포넌트 변수 추가 및 생성.
생성자에서 컴포넌트 셋팅. 회전속도 조절. 카메라 컴포넌트 생성
블루프린트로 추상화. BMCharacter 를 상속받는 FPCharacter 블루프린트 클래스.
메쉬 위치 조정.
Input 바인딩, 코드 델리게이터 메소드 연결.
GameMode 클래스 생성자에서 BMCharacter를 기본 폰으로 설정.
HUD 추가, 크로스헤어 그리기
void DrawHUD();
Canvas->DrawItem( TileItem );
발사체 만들기
BMProjectile 클래스 추가.
컴포넌트 : 구체 콜리전, 파티클, 메쉬, 발사체 이동
ABMProjectile::OnHit() 에서 파티클 생성.
발사체 스폰, 발사체 액터의 시작위치를 알려줄 SceneComponent 생성.
총구 위치로 셋팅해줌.
FPProjectile 블루프린트 클래스 생성, BMProjectile 상속.
블루프린트에서 비주얼 셋팅.
> 언리얼 로봇
AI분석하기
주요 요소들
AI Characters : AI 캐릭터는 PlayerController 가 아닌 AIController 에 의해 제어
Behavior Trees : AI 의사결정 시각적 표현.
7가지 고유한 노드 타입
Decorators, Services, Tasks, Selectors, Sequences, Simple Parallel, [Root]
AI Controllers : 모든 탐색 계산이 완료된 후 AI 캐릭터 이동을 담당. 조종. 커스텀 AI 컨트롤러 만들 수 있음.
Blackboard : 모든 AI 요소에 의해 검색, 할당될 수 있는 변수를 만들 수 있도록 함.
Navigational Meshes : NavMesh 볼륨 지역 내에서 지정된 AI 이동 에이전트 경로 생성 처리.
AI 통합을 위한 프로젝트 준비
PublicDependencyModuleNames.AddRange(new string[] { ... "AIModule" });
AI캐릭터 베이스 클래스
ABMBossCharacter : public ACharacter
첫 번째 AI 컨트롤러 만들기
ABMAIController : public AAIController
비헤이비어 트리 구성과 논리 흐름
비헤이비어 구성 기본 컴포넌트 이해. 요소와 설명
Root Node : 트리의 루트 포인트/엔트리 포인트. 트리가 실패하면 루트 노드부터 리셋.
Task Nodes : AI가 수행하는 작업. 이동, 회전, 대기 등. Task Nodes 를 상속한 블루프린트/C++ 오브젝트로 새롭게 만들 수 있음.
Service Nodes : 0.5초마다 특정 주기로 수행. AI에 주기적인 행동이나 확인을 수행. ex) 0.3초마다 교전하기에 충분히 가까운지 확인. Task Nodes 를 상속한 블루프린트/C++ 오브젝트로 새롭게 만들 수 있음.
Selector Nodes : 비헤이비어 트리 흐름 제어에 사용. 여러 자식 노드를 셀렉터 노드에 연결 가능. 셀렉터 하나가 성공할 때까지 자식 노드 왼쪽부터 오른쪽 방향으로 실행. 성공/실패에 따른 비헤이비어 트리 생성. 모든 하위 노드가 실패하면 셀렉터 노드 자체가 실패.
Sequence Nodes : 비헤이비어 트리 흐름 제어에 활용, 셀렉터 노드와의 차이는, 마지막 자식이 실패할 때까지 오른쪽에서 왼쪽으로 실행. 순서대로 실행해야만 하는 일련의 단계 만들 수 있다. 단계 중 하나가 실패하면 명령 중단, 트리 리셋. 모든 자식 노드가 성공하면 시퀀스 성공.
Simple Parallel Nodes : 두 자식 노드를 가짐. 테스크 노드, 혹은 완전한 서브 트리. 백그라운드에서 다른 동작 실행하면서 하나의 작업 수행. 테스크 자식은 옵션 데코레이터가 있는 하나의 태스크여야 함.
Decorator Nodes : 루트를 제외한 위 노드 타입들에 연결되며 실행 노드의 조건 검사 역할. ex) AI가 원하는 위치에 충분히 근접했는지 확인하는 데코레이터.
블랙보드란?
AI 에셋이나 오브젝트 내에서 읽기/쓰기 값 세트를 만드는 방법 제공.
블랙보드 키 : 값을 얻을 때 필요한 식별자. AI 네트워크 어디에서나 블랙보드에 저장된 데이터 유형을 검색/설정
기본적인 비헤이비어 트리와 블랙보드 만들기
보스 캐릭터에 AI 동작을 제공해본다. 보스가 플레이어를 목표로 인식하고 플레이어 쫓아가는 동작.
동작 : 플레이어가 보스와 멀리 떨어져 있거나 지형을 차단해 가려지면,
AI는 집 위치와 플레이어가 마지막으로 보인 위치를 왕복.
블랙보드 설정하기
콘텐츠 브라우저 우클릭 > Artificial Intelligence / Behavior Tree
콘텐츠 브라우저에서 Artificial Intelligence / Behavior Tree 생성.
블랙보드 편집기.
Behavior Tree 편집기. 우측 패널의 상단이 Details창, 하단이 Blackboard 창.
비헤이비어 트리에 블랙보드를 연결해야 함.
이렇게 디테일 창에서 블랙보드를 연결하고
연결되면 이런 모습으로 확인 가능.
위에서 생성한 블랙보드의 키값들 확인.
비헤이비어 트리 빈 영역을 우클릭하면 볼 수 있는 노드들의 목록. 우선 셀렉터 노드를 생성하고, 하위에 셀럭터 노드 1개, 시퀀스 노드 1개를 생성.
결과는 이런 모습. 노드의 우측 상단에 있는 숫자는 노드의 ID값.
셀렉터 노드에 데코레이터를 연결하는 모습. 블랙보드 값을 쿼리.
Flow Control 과 Blackboard 하위 셋팅을 적절히 맞춰주고. 여기서는 Aborts 를 Both 로.
시퀀스 노드에도 Is Not Set "TargetToFollow" 블랙보드 데코레이터를 추가하고, 하단에 MoveTo, Wait 태스크를 추가.
Behavior Tree 상단의 New Task 를 눌러서 커스텀 태스크를 추가한다.
특정 함수를 Override 해서 시작점을 재정의할 수 있다. My Blueprint 탭의 Function 항목에서 Override Function 에 하위의 Receive Execute 함수를 선택. 부모 노드에 의해 태스크가 실행될 때 호출될 함수.
결과적으로 이런 모습의 블루프린트 로직을 만들고, 이 태스크를 비헤이비어 트리의 셀렉터를 통해 호출하면 됨.
결과적으론 이런 모습.
이번엔 새로운 커스텀 데코레이터를 만들어본다.
Behavior Tree 에디터 상단의 New Decorator 버튼으로 생성.
이번에도 블루프린트로 로직을 작성한다. Perform Condition Check 함수를 오버라이드 해서 시작. 반환 타입을 가지는 함수로 boolean 타입을 반환해야 함. TargetToFollow 블랙코드 키의 액터가 특정 범위 내에 있는지 체크하는 로직을 작성한다.
블루프린트에서 사용할 변수 두 개, BMAIController 타입과 BlackboardKeySelector 타입.
작업을 위한 시작 준비 모습.
완성된 데코레이터의 블루프린트 로직.
이렇게 만들어진 데코레이터를
비헤이비어 트리의 MoveTo 태스크에 추가
이번엔 C++ 코드로 커스텀 서비스 만들기
서비스로 비헤이비어 트리의 AI 정보와 상태를 런타임 도중 업데이트. 블루프린트로 위의 태스트와 데코레이터를 만들어봤으니 서비스는 C++ 코드로 짜본다.
BTService 클래스를 상속받는 BMAgroCheck 클래스 생성. 주의, BTService_BlueprintBase 는 블루프린트용이니 무시.
LNK2001 에러가 발생한다면 ~.Build.cs 에 PublicDependencyModuleNAmes 에 라이브러리 추가해줘야 함.
에러 내용
2>BMAgroCheck.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskActivated(class UGameplayTask &)" (?OnGameplayTaskActivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>BMAgroCheck.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskActivated(class UGameplayTask &)" (?OnGameplayTaskActivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>BMAgroCheck.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskDeactivated(class UGameplayTask &)" (?OnGameplayTaskDeactivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>BMAgroCheck.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskDeactivated(class UGameplayTask &)" (?OnGameplayTaskDeactivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
해결
PublicDependencyModuleNames.AddRange(new string[] { ..., "AIModule", "GameplayTasks" });
TickNode 를 Override 해서 로직 작성.
리 체크해서 블랙보드 값들을 셋팅해주도록.
다음은 보스 캐릭터를 만들 차례
블루프린트 클래스를 만들고 아래와 같이 설정
커스텀 오브젝트 콜리전 채널 만들기
여기까지 하면 게임월드에 오브젝트 배치 준비 끝. 프로젝트 설정에서 콜리전 채널 생성.
Edit > Project Settings / Engine > Collision
여기서 Object Channels 와 TraceChannels 보이는 화면에서 New Object Channel...
처음 생성한 커스텀 채널이기 때문에 ECC_GameTraceChannel1 enum 값은 이 채널로 해석됨.
AI 지원을 위한 레벨 수정
네비게이션 메시 셋팅하기.
NavMesh 생성 설정 조절하기
Edit > Project Settings / Engine > NavigationMesh 이동
보스캐릭터 충돌 캡슐 크기 반경을 160으로 설정했으니, NavMesh 설정도 수정해줌.
Navigation System 의 Agents 항목 아래에도 Supported Agents 항목을 하나 추가한 뒤 Radious, Height 를 160, 320 으로 셋팅.
이제 신에 NavMesh 를 배치
Modes 패널에서 Nav Mesh Bounds Volume 을 생성.
Transform 패널에서 크기를 조절해주고.
월드 아울라이너에 RecastNavMesh-Boss
이 오브젝트는 Project Settings 에서 추가한 Supported Agents 인 Boss 에이전트에 대해서 생성된 것. Supported Agents 가 더 많았다면 RecastNavMesh 오브젝트가 더 생성됐을 것.
P 단축키로 뷰포트에서 NavMesh 를 볼 수 있음.
큐브를 몇 개 배치해보면
이렇게 장애물을 피해 NavMesh 가 만들어지는 걸 볼 수 있다. 녹색 영역이 길찾기 가능한 부분.
.
.
.