언리얼엔진

52. Tag 활용법 / AI Teleport 구현(Is At Location / 컴포짓)

찬이2 2023. 7. 24. 22:19

Tag를 통해 아군 / 적 구분하는 방법

먼저 BTS_FindTarget의 ReceiveSearchStartAI 이벤트를 함수로 변환하였다.

 

Actor Has Tag를 통한 구분

BTS_FindTarget의 ReceiveSearchStartAI 함수

AI로 감지된 대상들을 For Each Loop with Break로 하나씩 확인해주는데, Array Element를 로컬 변수로 승격하여 TargetNew를 하나 만든다.

그리고 원소 하나하나에 Tag A가 있는지 검사하고 있다면 TargetNew에 넣고, Loop가 끝나면 기존 Target변수에 TargetNew 값을 Set Blackboard Value as Object를 통해 넣어준다.

 

 

직접 감지된 대상의 Tag를 검사하여 구분

BP_Player / BP_Enemy에 먼저 Tag를 Team / A or B 순서대로 2개씩 각각 추가해준다.

 

BTS_FindTarget의 ReceiveSearchStartAI 함수

이번엔 Loop로 원소 하나하나마다 Tag를 뽑아와 먼저 Team 태그가 있는지 검사를 한다.

만약 있다면 Index + 1을 해주어 원소가 0보다 큰지 검사를 한다. 맞다면, Switch를 통해서 태그 1번째 원소를 가져와, A라면 TargetNew 로컬변수에 저장하고, Loop가 끝나면 Target에 TargetNew값을 넣어주며 종료한다.

 

여기서 Target을 찾지 못했다면 False로 A 태그를 찾지 못했다고 PrintString을 통해서 화면에 출력도 해봤다.

 

 

열거형과 인터페이스를 통한 팀 구분하기(권장하진 않음)

블루프린트 - 열거형을 추가하여 E_Team 하나를 만든다.

해당 열거형 안에 Team으로 팀으로 쓸 열거자들을 추가할만큼 추가한다.

E_Team 열거형

 

이후 BP_Character로 넘어와서 Team(E_Team) 변수를 새로 하나 추가한다. 기본값을 A로 지정했다.

그리고 BP_CharacterInterface에 GetTeam함수를 하나 추가하여 대상의 Team이 무엇인지 받아올 함수를 만든다.

 

그 뒤, Array Element의 Get Team과 현재 컨트롤중인 Get Team이 같은지 검사를 통해서도 구분해 볼 수 있다.

BTS_FindTarget의 ReceiveSearchStartAI 함수


혹은, 한 대상이 여러 팀에 속해있을 수도 있다고 한다면, E_Team 열거형에 와서 비트마스크 플래그를 활성화 해준다.

E_Team 열거형

 

그리고 BP_Character의 Team변수를 인티저 유형에, 비트마스크 활성화, 비트마스크 열거형을 E_Team으로 설정한다.

BP_Character의 Team 변수 설정

 

Team변수를 이와같이 설정했다면, 변수에 열거자를 동시에 여러개 설정해줄 수 있다.

Make Bitmask(E_Team 설정)를 통해 해당 열거자와 Team을 &연산으로 비교한게 0보다 큰지를 검사하여 팀을 구분해볼 수도 있다.

그리고 Team변수 값과 &연산을 통해서 확인해볼 수 있다.


BP_Enemy_Ranged의 텔레포트 AI 구현하기

Player가 BP_Enemy_Ranged와 일정거리 가까워지면, BP_Enemy가 Player 뒤의 특정 위치에 텔레포트 스킬로 이동하도록 해볼 것이다.

 

BT_Enemy_Ranged 비헤이비어 트리

Selector 밑에 만들었던 Sequence를 복사하여 하나를 더 붙혔다.

그리고 해당 Sequence 밑에는 저번에 만들었던 BTT_ActivateSkill 태스크를 이어준다.

여기서는 Switching Allowed를 True로, Skill Index를 1번으로 바꿔, Teleport 스킬을 활성화할 수 있도록 한다.


텔레포트 스킬이 활성화 됬다면, BTT_BeginActionA 태스크를 가져와 스킬을 사용하게 하고, 다시 BTT_ActivateSkill 태스크를 가져와 원래 FireBall 스킬을 활성화 하도록 바꿔준다.(Skill Index : 0)


BB_Enemy_Ranged 블랙보드에 와서 Destination(Vector) 키를 추가하여 만들어준다.

BB_Enemy_Ranged 블랙보드

 

BT_Enemy_Ranged 비헤이비어 트리의 Selector는 앞선 Sequence(Attack)가 실패해야만 뒤에 있는 다음 Sequence(Escape)를 실행한다.

따라서 앞선 Sequence(Attack)이 실패할 수 있도록 데코레이터를 추가해줄 것이다.

 

* Is At Location 데코레이터

특정 대상이 설정한 거리에 도달했냐를 물어보는 데코레이터이다.

Acceptable Radius : 50.0 / Blackboard Key에 Target을 주면 Target이 50.0만큼 접근됬다면 수행하도록 하는 것이다.

 

 

 

 

 

 

 

 

 

 

이 데코레이터를 각각의 Sequence에 추가하여 Sequence(Attack)에서는 1000.0의 거리를, Sequence(Escape)에서는 250.0의 거리를 설정해주고, Sequence(Escape)가 먼저 실행되어 검사되도록 순서를 바꿔주면 된다.

BT_Enemy_Ranged 비헤이비어 트리


다른 방법으로는 Sequence(Attack)에 IsAtLocation 데코레이터를 두 개 추가하고, Inversed Condition을 사용하는 것이다.

첫번째 Is At Location에서는 1000.0의 범위 안에 들어왔을 때 True이고, 두번째 Is At Location(inversed)은 250.0 범위 바깥에 있을 때 True이므로 Target이 250.0 ~ 1000.0 범위 안에 있을 때에만 True인 셈이다.

Is At Location의 Inversed Condition


* 컴포짓 데코레이터

위의 방법대로 한다면 Is At Location 두 개가 범위를 따진다는 면에서 같은 데코레이터라고 볼 수 있다.

따라서 컴포짓 데코레이터를 통해 하나만으로 검사할 수 있다.

 

컴포짓 데코레이터 내부

Sequence(Attack)에 컴포짓 데코레이터를 추가한 후, 컴포짓 안에 IsAtLocation을 두 개 추가하여 검사하는 것이다.

Is At Location 하나는 아까처럼 1000.0으로 설정, 다른 Is At Location 하나는 250.0으로 한 뒤, Inversed Condition을 활성화 해주고, 이 둘을 AND로 묶어서 Result로 내보낸다.

 

이처럼 컴포짓 데코레이터를 통해 두 개의 데코레이터를 하나로 묶어서 사용할 수 있다.


이제 AI가 Teleport를 사용할 경우에 맞춰 BP_Teleport에 별도의 처리를 해주어 AI에게 이동할 위치를 정해주어야 한다.

BB_Enemy_Ranged 블랙보드에 추가한 Destination 변수에 값이 저장되어 해당 위치로 텔레포트하면 된다.

 

이번엔 블랙보드로부터 직접 키를 받아와 값을 지정해보는 방식을 해본다.

 

BP_Teleport의 Get Destination Data 함수에서 PlayerController로 형변환에 실패했을 때의 분기를 통해 AI에게 위치를 지정해줄 것이다.

BP_Teleport의 Get Destination Data 함수

PlayerController로 형변환이 실패했단 것은 Player가 아니라는 뜻이므로 Instigator에서 바로 Blackboard를 받아와도 된다.

그리고 해당 블랙보드에서 Get Value as Vector로 특정 Key Name의 값을 받아올 것인데, Make Literal Name을 통해 Destination 키를 받아오도록 지정해주고, 해당 값을 반환(Location) 해준다.

 

이후 BP_Teleport 이벤트그래프로 나와서 End Action A 이벤트 로직 초반에 Branch로 Get Destination Data 함수 값 검사를 하지 않도록 Branch를 제거해준다.