📚 Targeting
플레이어의 앞에 Enemy 여러명 위치해있을 때, 일정 타겟팅 범위 내에 존재하는 Enemy 중 Camera Front 방향으로부터 가장 가까운 Enemy를 타겟팅하는 기능을 구현해보았다.
Targeting을 구현하는 모든 내용은 TargetComponent를 생성하여 그 안에서 구현한 뒤, 플레이어의 컴포넌트로 추가해주었다.
1. 타겟 범위 내 Enemy 찾기
플레이어를 중심으로 Trace Distance(1000) 범위 이내에 존재하는 Enemy를 찾기 위해 MultiSphereTracceByProfile 함수를 사용하였다.
MultiSphereTracceByProfile 함수는 특정 profile을 사용하여 범위내에 충돌되는 Hits 배열을 반환해준다.
프로젝트 세팅의 콜리전에서 새 프로파일을 추가하여 범위 내에서 블록 충돌(Trace는 모두 블록 충돌이다, Physics Only) 콜리전을 수행하고 오브젝트 유형이 Pawn인 액터들만 검색하는 프로파일을 만든다.
(근데 사실 오브젝트 유형은 누군가와 충돌할 때 필요한건데, 나는 프로파일을 가지고 검색만 하기 때문에 뭐든 상관없다)
이렇게 만들어진 프로파일을 함수의Profile Name에 입력하면 Pawn이 블록되어있는 액터만 배열에 담아 반환해주게 된다.
이제 나머지는 추적할 거리 Trace Distance(1000)과, 액터 자신을 제외시킬 character 배열을 만들어 Ignore에 연결하고, 범위를 확인하기 위한 Draw Debug를 생성하여 연결해주었다.
그 결과, 다음과 같은 추적범위 내 Enemy들이 반환되었다.
2. 타겟 범위 내 Enemy 중, 가장 가까운 타겟 지정하기
반환된 Element 들을 중, Class 타입을 비교하여 같은 Class 타입이 아닌경우, 즉, 아군이 아닌경우만 Targets 배열에 추가해주었다.
프로파일 내 모든 Element의 for문이 끝나면 만들어진 Targets 배열의 Character들 중, 플레이어(Character)와 가장 가까운 타켓을 찾아서 현재 Target으로 설정하는 Change Target 함수를 호출하였다.
가장 가까운 타겟을 찾는 Get Nearly from Camera Front 함수는 이전에 만들어둔 함수로, 이전 게시글에 정리하였다.
Change Target 함수가 호출되었을 때 검색된 가장 가까운 타겟이 없다면, 타겟팅을 끝내는 End Targeting 함수를 호출하였다. 반대로 가까운 타겟을 찾았다면 찾은 타겟을 구별하기 위해 아우라 파티클을 출력해주었다.
End Target 함수에서는 간단히 Target을 NULL로 설정하고, 파티클이 존재한다면 Destroy 시켜주었다.
그 결과, 추적범위 내 검색된 Enemy 중, 플레이어의 가장 앞에 가까이 위치한 Enemy에게 파티클이 성공적으로 출력되었다.
3. 타겟이 있다면 타겟을 바라보도록 설정하기
타겟이 존재한다면 Tick 이벤트에서 Tick_Targeting 함수를 호출하여 플레이어가 타겟을 바라보도록 설정하였다.
RInterp To 함수를 통해 보간을 적용하여 부드러운 시점 이동을 구현하였다.
이때, 실제 게임과 같이 왼쪽, 오른쪽 시점만을 타겟에게 고정시키고, 위아래 시점은 자유롭게 움직일 수 있도록 구현하였다. 따라서 플레이어의 Pitch 회전은 그대로 가져가고, Roll, Yaw 회전만 Find Look at Rotation 함수를 이용하여 타겟을 바라보도록 설정하였다.
RInterp To 함수로 보간을 적용하였고, 각도의 허용 오차값 2도안에 회전값이 맞춰지면 제대로 바라보도록 Set Controll Rotation을 마지막으로 초기화해주었다.
4. 타겟 왼쪽, 오른쪽으로 옮기며 설정하기
플레이어의 앞에 위치한 Enemy를 타겟으로 설정한 뒤, 해당 타겟으로부터 왼쪽에 가장 가까운 Enemy로 타겟을 변경하거나, 오른쪽에 가장 가까운 Enemy으로 타겟을 변경하는 기능을 구현하였다.
쉽게말해, 타겟을 잡은 후 Q, E 키보드 값을 주면 왼쪽, 오른쪽에 있는 Enemy로 타겟을 다시 잡는것이다.
이렇게 타겟이 왼쪽에 존재하는지 혹은 오른쪽에 존재하는지를 판별하는 방법은 "외적"을 이용해야 한다.
외적은 따로 예제를 만들어 게시글에 설명해두었다.
2023.02.14 - [Unreal4] - [UE4] 외적(Cross), Sign함수
키보드 T값을 입력하면 Targeting 토글을 실행시키고, Q를 누르면 Left Targeting, E를 누르면 Right Targeting이 실행되도록 구현하였다.
타겟의 포커스를 변경하는 Change Focus 함수에서 가장먼저 (Enemy 벡터 - 플레이어 벡터)를 Normalize하여 플레이어-> Enemy로 향하는 방향벡터를 구하고, 플레이어의 Forward 벡터와 외적(cross)한다.
외적한 결과를 다시 플레이어의 Up벡터와 내적(dot)하면 Enemy가 Player의 오른쪽에 있다면 양수값, 왼쪽에 있다면 음수값이 나온다. 그리고 더 멀리 있을 수록 값이 크게 나온다.
이런 외적->내적의 결과를 Map 변수에 저장하는데 Key값은 내적의 결과 float 값으로 저장하고, Value값은 해당 내적을 계산한 대상 Enemy를 Character 변수 유형으로 저장한다. (나중에 Key값으로 비교하기 위함)
위와 같은 과정을 타겟팅 범위(Trace Distance)내에 검색된 모든 Enemy를 대상으로 for문을 돌리며 Map 변수에 추가하였다.
(이 과정은 위에 외적을 설명한 게시글과 같은 내용이므로 이해가 안간다면 외적 게시글을 다시 정독하자)
모든 Enemy 연산이 끝나면 Key값을 비교하며 다음 Target이 될 가까운 Enemy를 찾아야하는데, Enemy가 오른쪽에 있다면 Key값이 가장 작은값, 왼쪽에 있다면 Key값이 가장 큰값을 찾으면 된다.
그러나 두 경우를 모두 따지지 않고 Key값에 절댓값을 취하면 그냥 가장 작은 값을 찾으면 되므로 ABS 함수를 이용하여 절댓값으로 비교해주었다.
타겟의 포커스를 옮기려는 방향이 오른쪽이면(In Right == True) Key 값이 0보다 큰값들 중 최소값을 찾고, 방향이 왼쪽이면(InRight == False) Key 값이 0보다 작은 값들 중 최소값을 찾는다.
가장 작은 값을 Minimum(float형) 변수에 저장해두고, Map 변수에서 해당 키값으로 Character를 찾아 Candidate 변수에 저장하였다.
모든 for문이 끝나면 다음 타겟이 저장된 Candidate 변수가 찾아지므로, Change Target 함수로 타겟을 변경하고 Change Focus 함수가 종료된다.
'🎮Unreal4 > Blueprint' 카테고리의 다른 글
[UE4] Parkour 기능 -2 (Climb, Set Movement Mode, 루트 모션) (0) | 2023.02.16 |
---|---|
[UE4] Parkour 기능 -1 (파쿠르가 가능한지 검증, Trace Channels) (0) | 2023.02.15 |
[UE4] 외적(Cross), Sign함수 (0) | 2023.02.14 |
[UE4] IK 구현하기 -2 (Two Bone IK(2본IK), 로컬을 컴포넌트로/컴포넌트에서 로컬로) (0) | 2023.02.13 |
[UE4] ZoomIn/ZoomOut, Interp To 함수(FInterp To, RInterp To, VInterp To) (0) | 2023.02.13 |