안녕하세요 '언리얼로 만들어보는 RPG'의 필자입니다. 저번 글에서 Drag&Drop까지 처리했다면 참 좋겠지만 안타깝게도 분량조절에 실패하는 바람에 이렇게 뒤로 밀리게 되었습니다.


그런고로 오늘은 Drag&Drop을 해볼예정입니다만 필자도 처음 작업할때 감을 잡기가 어려워서 언리얼 공식문서의 튜토리얼을 참고했었습니다. 혹시 관심이 있는분이 있으실지 모르니 링크를 남겨두겠습니다. 별로 의미는 없는 여담이지만 필자의경우 멍청하게 영어버전을 찾아서 작업했었습니다. 여러분은 편하게 한글로 보고 하시면 됩니다.


언제나 새로운 작업을 시작할때는 대충이라도 전체적인 방식에 대한 그림을 그려두시는게 좋습니다. 필자의 경우에는 Slot UI에서 작업을 할 생각이며 실질적으로 Drag&Drop을 통해서 인벤토리의 정보가 바뀌는 부분은 PlayerBase쪽에서 할 것입니다. 그 중간에 Inventory UI에서도 거쳐가는 함수를 만들 예정입니다.


대충 정리해보자면

1. Drag를 시작할때 해당 Slot의 번호와 Type을 저장

2. Drop을 하게되면 PlayerBase에서 시작 Slot과 Drop Slot의 정보를 전달

3. 전달받은 정보를 기반으로 인벤토리를 Swap

이정도로 정리가 될것 같습니다.


Drag&Drop을 할때 관여되는 클래스가 있는데 해당 클래스는 (&)DragDropOperation입니다. 필자는 지금까지와 마찬가지로 해당 클래스를 상속받아서 Slot의 Drag&Drop용 클래스를 만들어서 처리해 줄 것입니다.


SlotDrag.h

필자는 상속을 받아서 SlotDrag라는 클래스를 만들었습니다. 막상 딱히 해줄건 없고 Drag를 시작한 Slot의 num과 해당 Slot의 타입을 기억해줍니다.


Slot.cpp

아이템 사용은 우클릭으로 했으니 Drag&Drop은 좌클릭으로 처리하겠습니다. 새롭게 추가된 코드에서 DetectDragIfPressed함수는 Blueprint/WidgetBlueprintLibrary.h를 추가해 줘야합니다. 해당 함수는 인자로 들어온 버튼이 눌린상태로 Drag를 했는지 잡아내 주는 함수입니다.


Slot.h

DragDropOperation을 이용하려면 위 이미지에 나오는 NativeOnDragDetected, Drop을 오버라이딩 해주셔야합니다. 그리고 Drag를 하는동안 마우스를 따라 보여줄 UI클래스를 에디터에서 설정해주도록 합니다.


Slot(UMG에디터)

빌드를 해보신다면 저렇게 클래스를 설정해줄 수 있게됩니다. 저희는 이미 Widget을 준비해둔 블루프린트 클래스가 필요하니 꼭 BpSlot으로 설정하셔야 합니다.


Slot.cpp

OnButtonDown함수에서 왼클릭을 했을때 DetectDragIfPressed함수를 통해서 OnDragDetected함수가 불러집니다. 이후에는 별거 없습니다. 아까 상속받아서 만든 SlotDrag클래스를 새로 만들어주고 Drag를 시작한 Slot의 num과 type을 넣어줍니다.


그 다음에 아까 에디터상에서 클래스를 설정해주어서 nullptr이 아니라면 새롭게 만들어 type, Player포인터, num을 채워주고 Refresh함수를 부릅니다. 해당함수는 Slot UI를 갱신해줍니다. 이렇게 새로 만든 Slot을 SlotDrag의 DefaultDragVisual에 대입해줍니다. 해당 변수는 Drag를 하는동안 따라다닐 UI를 가지는 변수입니다.


Slot.cpp

Drag도중 마우스를 떼면 OnDrop함수가 호출이 됩니다. 물론 반드시 호출되는건 아니고 확인해본 결과 OnDragDetected함수의 인자 OutOperation가 nullptr이라면 Drop은 불러지지 않습니다.


Slot에 Drop이 된다면 PlayerBase에 만들어둔 DraggingSwap함수로 두 Slot의 정보를 전달해 줍니다. 방식이 좀 왔다갔다 하는편이라서 한눈에 잘 안들어 오실수도 있지만 양해 부탁드리겠습니다.


PlayerBase.h

<새롭게 추가한 함수 DraggingSwap, SwapInven>

PlayerBase.cpp

좀 번거롭기는 하지만 Drag&Drop을 반드시 인벤토리에서만 하리라는 법은 없기때문에 거쳐가는 함수를 하나 만들었습니다. DraggingSwap함수에서는 들어온 두 슬롯의 정보를 기반으로 어떤 Swap함수를 부를지 정해줍니다. 지금당장은 인벤토리에서만 Swap하는걸 작업하기 떄문에 그거말고는 없습니다.


Slot의 type이 둘다 Item이라면 SwapInven함수에 해당하는 번호들을 전달해줍니다. 이후 인벤토리 배열에서 해당 인덱스들을 Swap해주고 Slot UI를 갱신하기 위해서 GameUIWidget에 만든 RefreshInventory함수를 불러줍니다.


GameUI.cpp


Inventory.cpp

이후에는 위의 두 함수가 차례대로 불러지면서 Slot UI의 이미지를 갱신해줍니다. 그리고 빌드를 돌려서 테스트 할 일만 남았군요 이제


<길고긴 고생끝에 성공한 Drag&Drop>


필자는 이게 성공했을때 너무나 감격했었습니다. DragDropOperation에 대한 정보는 너무 없었고 이걸 사용하는 예제도 찾지 못헀었기때문에 순전히 필자 스스로의 힘으로 만들어야 했었기 때문입니다. 지금 읽고 계시는 여러분도 직접 코드를 작성해서 돌아가는걸 보게된다면 똑같은 기분은 아닐지언정 상당히 뿌듯해지지 않을까 감히 예상해봅니다.


이번에도 글이 좀 길어진것 같지만 읽어주셔서 감사합니다. 아마 다음글은 멀지 않은날에 쓸거 같고 HP나 경험치를 보여주는 Bar를 만들 예정입니다. 모두들 이번주의 시작을 기분좋게 마무리 하셨기 바랍니다.

Posted by 별수집가
,