본문 바로가기

언리얼엔진

16. 매크로 라이브러리 / 구조체 / DataAsset

오늘꺼 너무 어렵따....ㅠ


입력된 방향에 맞춰 Roll 애니메이션 구현하기

현재 Roll의 방향은 캐릭터의 전방으로 나간다. 따라서 입력된 방향키에 맞춰서 캐릭터의 전방을 회전시켜주면 된다.

BP_Character에서 Character Movement를 받아올 때 캐릭터의 전방을 입력된 키에 맞춰 회전시킨다.

Make Rot from X 노드

 

Make Rot from X 노드를 통해서 Character Movement에 마지막으로 입력된 Vector값을 X축으로 삼는 Rotator를 만든다.

그리고 만들어진 Rotator를 현재 캐릭터(Actor)의 Rotation에 적용시켜주면 해결이 된다.

Make Rot from X → SetActorRotation → Roll Montage

이렇게 입력된 방향에 맞게 Roll 애니메이션이 바로바로 적용되도록 수정해봤다.


소켓에 생성한 무기 붙이기

BP_Weapon에서 변수 2개를 만들어준다.

- SocketOnEquipped - type 이름 : 무기를 장비했을 때(오른손)

- SocketOnUnequipped - type 이름 : 무기를 장비하지 않았을 때(등 뒤)

BP_Weapon에서 변수 생성

 

컴파일 후에, 자식 클래스인 BP_Sword에 와서 위의 두 변수에 각각 무기가 있어야할 소켓의 이름을 넣어준다.

자식클래스 BP_Sword에서 알맞는 소켓의 이름을 넣어줌

 

※ 주의할 점!

위의 경우처럼 문자열에 의존하여 처리하는 로직은 위험한 방식 중 하나이다.

한 글자라도 틀리게된다면 바로 논리적 오류가 발생하기 때문이다.

하지만 아예 사용하지 않을 수는 없기애 문자열을 받아오는 곳을 한 곳으로 일원화를 시켜 사용하는 것이 좋다.


BP_Weapon에서 만든 SocketOnEquipped / SocketOnUnequipped 변수들을 수정하지 않고 가져다만 쓰도록 하기 위해서

해당 변수를 블루프린트 읽기 전용으로 체크해준다.

이를 통해 해당 변수들은 블루프린트에서 Getter만 가져다 사용할 수 있다.(Run 타임에서 수정이 안됨)

SocketOnEquipped / SocketOnUnequipped 둘 다 체크

 

다음으로 BP_Character에서 함수(AttachActorToMesh / EquipWeapon / UnequipWeapon)를 만들어 준다.

AttachActorToMesh 함수는 Actor를 Mesh에 붙여주는 역할을 해줄 함수이다.

EquipWeapon 함수는 입력받은 Weapon을 Socket(hand_r_weapon)에 붙여주는 역할을 해줄 함수이다.

UnequipWeapon 함수는 입력받은 Weapon을 Socket(spine_03_weapon)에 붙여주는 역할을 해줄 함수이다.

3개의 함수를 생성한다.


AttachActorToMesh 함수

AttachActorToMesh함수에서 입력 받아올 것은 Actor(오브젝트)와 Socket(이름)을 받아오게 된다.

그리고 Skeletal Mesh안에 있는 Socket에다 Actor(Sword)를 붙인다.

입력으로 Actor / Socket을 받아온다.

 

AttachActorToMesh 함수(Attach Actor to Mesh → Is Valid 실행핀 연결 필요)

먼저 입력으로 받아온 Actor 오브젝트 레퍼런스가 Is Valid에서 None인지 아닌지를 판단한다.

이를 통해 Actor에 None값이 들어오는 것을 막을 수 있다.

다음으로 AttachActorToComponenet를 통해 Mesh Componenet의 소켓에 Actor를 붙일 것이다.

 

- 타겟 : 입력으로 받아온 Actor

- Parent : 타겟을 붙여줄 SceneComponent(Mesh Component)

- Socket Name : 입력에서 받아온 Socket(SkeletalMesh에서 만들었던 Socket을 말함)

 


EquipWeapon 함수

입력에 Weapon을 추가해준다.(BP Weapon 타입)

BP_Weapon 타입을 받아올 입력값을 추가해준다.

 

EquipWeapon 함수

이번에도 입력 받은 Weapon을 Is Valid로 유효성 검사를 거쳐서 Attach Actor to Mesh로 붙여주는 방식이다.

Attach Actor to Mesh에서 Actor는 입력받은 Weapon이고 Socket은 BP_Weapon에서 만든 변수 Socket on Equipped를

연결시켜 주면서 무기 장비 시, hand_r_weapon 소켓으로 Weapon을 붙여주게 된다.


UnequipWeapon 함수

입력으로 BP_Weapon타입을 받아온다.

BP_Weapon 타입을 받아올 입력값을 추가해준다.

 

UnequipWeaon 함수

마찬가지로 입력받은 Weapon의 유효성 검사를 거친 후 Attach Actor to Mesh로 붙여주게 된다.

달라지는 것은 붙여주는 Socket이 Socket on Unequipped(spine_03_weapon)으로 바뀌는 것이다.


이제 스폰된 무기를 우리가 지정해준 소켓으로 붙혀주기 위해 BP_Character의 BeginPlay 이벤트 시작이되서 무기가

생성되는 시점으로 간다.

우선 처음에는 무기를 장착한 상태가 아니므로 UnequipWeapon 함수를 통해 무기를 등 뒤의 소켓에 붙여줄 것이다.

Weapon Class에 기반하여 Actor를 생성하고 Weapons 컨테이너에 저장한 다음, UnequipWeapon의 소켓 위치에 붙여준다.

 

이후 실행해보면 캐릭터 등 뒤의 Socket에 칼이 붙어있는 것을 볼 수 있다.


Weapon A 이벤트를 통해 무기 장착하기

우리가 만들었던 Weapon A와 Weapon B는 장착하는 무기만 달라질 뿐 작동하는 방식이 똑같다고 할 수 있다.


블루프린트 매크로 라이브러리

콘텐츠브라우저에서 콘텐츠/Blueprints 폴더 안에 우클릭 - 블루프린트 - 블루프린트 매크로 라이브러리를 추가해준다.

블루프린트 매크로 라이브러리는 전역에서 사용할 수 있는 매크로들을 담아놓은 라이브러리다.

따라서 어느 블루프린트 클래스에서든 사용할 수 있다.

블루프린트 매크로 라이브러리 추가

 

블루프린트 매크로 라이브러리를 추가하게되면 부모 클래스를 선택하는 창이 나올 것이다.

매크로에 부모 클래스란, 어느 클래스까지 영향을 미칠 것인지를 정해주는 것을 말한다.

그래서 우리는 모든 곳에서 사용이 가능하도록 밑에 모든 클래스를 펼친 뒤, Object(최상위 클래스)를 선택해주었다.

Object(최상위 클래스)를 선택함

 

해서 이렇게 콘텐츠/Blueprints 폴더 안에 블루프린트 매크로 라이브러리(ObjectMacros)를 생성하였다.

블루프린트 매크로 라이브러리(ObjectMacros) 생성

 

블루프린트 매크로 라이브러리의 첫 화면이다.

 

ObjectMacros 안에서 새 매크로 두개를 추가해준다.

LocalVariable(지역변수)과 DefaultTransform으로 만들었다.

 

LocalVariable(지역변수) 매크로는 기본적으로 로컬 와일드카드를 사용한다.

LocalVariable 매크로 : 로컬 와일드카드를 추가하여 출력과 연결

 

DefaultTransform 매크로는 Make Transform을 사용한다.

DefaultTransform 매크로 : Make Transform을 추가하여 출력과 연결


BP_Character에서 방금 정의한 매크로 Local Variable 매크로를 추가해준다.

변수 Get Weapons를 추가해서 Get 노드를 뽑아내 Local Variable 매크로와 연결시켜주어 와일드카드의 타입이 확정된다.

Local Variable의 값을 설정해주기 위해서 레퍼런스 변수 설정 노드를 뽑아준다.

 

Weapon A와 레퍼런스 설정 노드를 연결해주었다면 Weapon B도 똑같이 레퍼런스 설정 노드를 추가해서 연결시켜주었다.

Weapon A와 Weapon B는 Weapons 배열에 있는 몇 번 원소를 가져올 것인지 서로 다르고 뒤의 내용은 서로 같다.

따라서 배열의 인덱스 설정만 각각 몇 번을 가져올 것인지 바꿔주기만 하면 된다.

그래서 Weapon A의 Value는 0, Weapon B의 Value는 1로 설정하였다.


Local Variable에 Weapons배열의 인덱스를 담아뒀다면 이후 각각 어떤 무기를 들게될지 설정이 되었고 무기를

장착하기 전에 먼저 현재 상태가 Idle인지 판단할 것이다.

Is State를 통해서 Weapon A / B 이벤트 발생 시 둘 다 현재 Idle 상태인지 Branch를 통해서 확인해주고,

true일 때만 Set State를 통해서 현재 상태를 Arming으로 바꿔주었다.

마지막으로 EquipWeapon 함수의 Weapon을 Get에서 받아오면서 몇 번째 무기를 장착할 지 보내준다.

 

이제 컴파일 후 실행하여 지정했던 Weapon A 이벤트 키인 Q를 누르면 EquipWeapon에서 정해둔 hand_r_weapon 소켓에

무기가 위치하는 것을 볼 수 있다.


무기 장착 시 Draw 애니메이션의 세분화

구조체

무기를 꺼낼 때 등 뒤에서만 꺼내는 것이 아닌 다른 곳에서도 꺼낼 경우가 있을 것이다.

이렇게되면 때에 따라서 서로 다른 애니메이션이 필요로 하게 된다.

 

콘텐츠브라우저의 콘텐츠 폴더에서 우클릭 - 블루프린트 - 구조체를 생성한다(PlayMontageParameters)

PlayMontageParameters 구조체 생성

 

PlayMontageParameters 구조체의 첫 화면

 

이 구조체는 Play할 Montage를 담아 사용할 것이다. 3개의 변수를 추가해주었다.

- Montage - type Anim Montage : 플레이할 몽타주

- PlayRate - type Float : 재생 속도(기본값으로 1.0)

- Section - type Name : 색션의 이름

PlayMontageParameters 내부의 변수 설정


DataAsset

콘텐츠 브라우저의 콘텐츠/Blueprints 폴더 내에 우클릭 - 블루프린트 클래스를 새로 생성해줄 것이다.

부모 클래스 선택에서 PrimaryDataAsset을 선택하여 생성해준다.

PrimaryDataAsset(BP_MontageDataAsset) 생성

 

BP_MontageDataAsset 내부에서 새 변수 MontageData를 만들어준다. type은 위에서 만들었던 PlayMontageParameters

구조체로 설정해주며 배열로 설정한다.

 

 

다시 콘텐츠 브라우저로 돌아와서 콘텐츠/Blueprints 폴더 안에 우클릭 - 기타 - 데이터 애셋을 하나 추가해준다.

데이터 애셋 클래스 선택은 아까 만들었던 BP_MontageDataAsset을 선택해준다.

 

이러면 다음과 같은 아이콘을 가진 DataAsset(SwordArmnigData)가 생성된 것을 볼 수있다.

 

SwordArmnigData을 보면 BP_MontageDataAsset을 기반으로 만들었기 때문에 MontageData 배열이 보일 것이다.

Montage Data의 엘리먼트를 +하여 추가해보면 아까 만든 PlayMontageParameters 구조체의 형식을 볼 수 있다.

 

이제 해당 원소에 넣어줄 Montage를 만들기 위해서 Draw_1 애니메이션의 몽타주를 생성한다(Draw_Montage).

다음으로 Draw_Montage 내부에서 Draw_1과 Draw_2 애니메이션을 서로 붙여서 나오도록 만든다.

Draw_1의 애님 몽타주 생성(Draw_Montage) -> Draw_Montage에서 Draw_1과 Draw_2 애니메이션을 붙임

 

이렇게 만든 Draw_Montage를 다시 SwordArmingData 데이터 애셋의 0번째 원소 Montage에 넣어서 지정해준다.

Draw_Montage를 넣어줌


다음으로 BP_Weapon에서 새 변수 MontageDataMap을 만들어 준다.

이 변수는 state에 따라 Montage의 목록을 가지고 있을 것이다.

따라서 type은 E_Character_State으로 해주고, 유형은 맵으로, 맵의 값은 BP_MontageDataAsset으로 설정하였다.

 

이후 컴파일하여 MontageDataMap 변수의 기본값을 보면 특정 state에 따라서 Montage를 지정해줄 수 있다.


BP_Weapon의 BeginPlay를 통해서 현재 MontageDataMap에서 FIND를 뽑아 Idle state의 원소를 찾는다.

이후 Idle State의 MontageData배열의 0번째 원소의 Montage의 이름을 플레이 화면에 출력해볼 것이다.

 

하면 플레이 시에 좌측 상단에 해당하는 Montage의 이름이 출력되는 것을 볼 수 있다.

지금은 이름이 출력됬지만 이것을 이용해 PlayMontage에 넣으면 애니메이션이 나올 수 있을 것이다.


만약에 ADD를 통해서 Idle상태의 MontageData에 PlayMontageParameters를 만든다면 런타임 중에 수정된 내용이

그래도 반영되는 것을 볼 수 있을 것이다.

이를 막기 위해서 몇가지 방법을 생각해보자.

BP_Weapon에서 Make PlayMontageParameters를 통해 ADD
SwordArmingData에 바로 반영된 모습