Unreal - 인벤토리(3) (드래그 앤 드롭)

2025. 11. 25. 00:25·Unreal 프로젝트 다이어리/두번째 프로젝트

이전 글에서 이어집니다

2025.11.23 - [Unreal 프로젝트 다이어리/두번째 프로젝트] - Unreal - 인벤토리 ( 아이템 추가하기 )

 

Unreal - 인벤토리 ( 아이템 추가하기 )

이전글에서 이어집니다2025.11.22 - [Unreal 프로젝트 다이어리/두번째 프로젝트] - Unreal - 인벤토리 (크기변경하기, 창옮기기) Unreal - 인벤토리 ( 크기변경하기, 창옮기기 )인벤토리를 구현해보겠습니

lucodev.tistory.com

 

아이템 드래그앤드롭 기능을 추가하였습니다

 

구현한 내용

  • 인벤토리 드래그 앤 드롭

구현방식

1. NativeOnMouseButtonDown에서 원본 슬롯을 반투명 처리하고 드래그 시작 감지.

2. NativeOnDragDetected에서 DragDropOperation 생성, 마우스를 따라다니는 드래그 비주얼 설정,

Drop/Cancel 시 원본 슬롯 복구.

 

사용한 클래스

SlotWidget 인벤토리 슬롯 UI, 아이템표시 + 드래그 / 드롭 처리
InvenSlotReplicateWidget 드래그 중 마우스를 따라다니는 아이템 비주얼 위젯
InventoryDragDropOper 드래그 중 아이템 데이터와 DragVisual을 담는 컨테이너

 

 

 

구현

언리얼 엔진에서 드래그 앤 드롭 시스템을 구현할때 드래그 중인 아이템의

정보 + 비주얼 을 담을수있는 상태를 담는 컨테이너 객체를 제공합니다

 

이름은 DragDropOperation이며 해당 클래스로 만들어주시면됩니다

 

목적은 이와 같습니다

드래그 중인 아이템의 데이터를 담는 컨테이너클래스 이며

드래그가 진행되는동안 드롭할 때 어떤 아이템인지 알려주기 위해 사용됩니다

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/DragDropOperation.h"
#include "ItemSlot.h"
#include "InventoryDragDropOper.generated.h"

UCLASS()
class PORTFOLIOMS_API UInventoryDragDropOper : public UDragDropOperation
{
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere)
	int32 startSlotIdx = -1;

	UPROPERTY(EditAnywhere)
	int32 itemID = -1;

	UPROPERTY(EditAnywhere)
	int32 count = 0;

	UPROPERTY(EditAnywhere)
	FItemSlot dragSlot;
	
};

 

먼저 InventoryComponent에서 인벤토리는 TMap으로

키와 밸류 값으로 이루어져있습니다 TMap<int32, FItemSlot>

TMap의 FItemSlot 을 바꿔주는 즉 인벤토리를 서로 바꿔주는 Swap 함수를 만들어주어야합니다

해당 함수는 인벤토리 기능을 담당하는 InventoryComponent에서 만들어주었습니다

 

출발 슬롯과 목적지 슬롯의 FItemSlot값을 서로 임시변수로 교환하여

두 슬롯의 내용을 바꿔줍니다

void UInventoryComponent::SwapItem(int32 startIdx, int32 destinationIdx)
{
	FItemSlot destinationSlot = items[destinationIdx]; // 목적지 슬롯 기존 아이템
	items[destinationIdx] = items[startIdx];           // 목적지 {itemID = 88, inCount = 88}
	items[startIdx] = destinationSlot;                // 출발지

	onInventoryUpdated.Broadcast(startIdx, items[startIdx]);
	onInventoryUpdated.Broadcast(destinationIdx, items[destinationIdx]);
}

 

 

블루프린트로는 구현하기 쉬웠는데 c++로 구현할려니 막막하더라구요

구글링과 공식문서를 뒤적거리다가 이와같은 함수가 있다 라는것을 알았습니다

 

위젯에서는 드래그할때  이와같은 함수를 오버라이드 하여 사용할수있습니다

NativeOnMouseButtonDown 사용자가 위젯에서 마우스 버튼을 눌렀을 때 호출
NativeOnDragDetected 마우스를 눌러 드래그를 시작한 것을 감지했을 때 호출되는 이벤트
NativeOnDrop 위젯에 드래그된 오퍼레이션이 놓였을 때 호출되는 이벤트, 드롭 처리(데이터 이동, 교환 등)를 수행.
NativeOnDragCancelled 드래그 도중 취소

 

이와같이 오버라이드 하여 사용합니다

virtual FReply NativeOnMouseButtonDown(const FGeometry& inGeometry, const FPointerEvent& inMouseEvent) override;
virtual void NativeOnDragDetected(const FGeometry& inGeometry, const FPointerEvent& pointerEvent, UDragDropOperation*& outOperation) override;
virtual bool NativeOnDrop(const FGeometry& inGeometry, const FDragDropEvent& inDragDropEvent, UDragDropOperation* inOperation) override;
virtual void NativeOnDragCancelled(const FDragDropEvent& inDragDropEvent, UDragDropOperation* inOperation) override;

 

SlotWidget에 이와같이 추가해줍니다

public:
	class UInventoryComponent* inventoryComp;
	FItemSlot currentSlotData;

	UPROPERTY(EditAnywhere)
	TSubclassOf<UInvenSlotReplicateWidget> replicateWidget;

	void SetDraggingVisual(bool bDragging);

public:
	int32 slotIdx = -1;

 

슬롯 내에서 NativeConstruct내에서 사용하고있는 pawn에서 원하는 컴포넌트를 먼저 캐스팅해줍니다

inventoryComp = myPawn->FindComponentByClass<UInventoryComponent>();

 

NativeOnMouseButtonDown 함수입니다

좌클릭의 신호를 받을때 신호를 처리합니다

 

FReply USlotWidget::NativeOnMouseButtonDown(const FGeometry& inGeometry, const FPointerEvent& inMouseEvent)
{
	if (inMouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
	{
		if (!currentSlotData.isEmpty()) //있을때만 처리
			return UWidgetBlueprintLibrary::DetectDragIfPressed(inMouseEvent, this, EKeys::LeftMouseButton).NativeReply;
	}
	return FReply::Unhandled();
}

 

 

 

 

 

드래그도중 호출되는 NativeOnDragDetected 함수입니다

아까만든 DragDropOperation에서 변수값을 현재 슬롯의 데이터와 동기화하고

드래그 비주얼 위젯을 생성하여 아이콘을 반영합니다

(SetDraggingVisual 함수 커스텀 함수이며 바인딩 된 이미지, 텍스트의 Alpha값을 조절합니다)

 

여기서 정말 많이 삽질했는데 

처음에 삽질한 코드를 보자

//삽질코드
dragOper->DefaultDragVisual = this;
this->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
outOperation = dragOper;

 

이러면 가끔 슬롯이 감지 안되는 레이아웃 클릭 충돌 문제가 있었다

위젯 리플릭터로 디버깅해보니 감지가 잘 안되던문제가 있었다

즉 복제위젯이 따로 별도로 만들어야만했다

 

그리고 InvenSlotReplicateWidget이란 드래그할때 보여지는 위젯을 별도로 만들었다

void USlotWidget::NativeOnDragDetected(const FGeometry& inGeometry, const FPointerEvent& pointerEvent, UDragDropOperation*& outOperation)
{
	if (currentSlotData.isEmpty() || !inventoryComp)
		return;
	SetDraggingVisual(true);
	UInventoryDragDropOper* dragOper = NewObject<UInventoryDragDropOper>();
	dragOper->startSlotIdx = slotIdx;
	dragOper->itemID = currentSlotData.itemID;
	dragOper->count = currentSlotData.inCount;
	dragOper->dragSlot = currentSlotData;

	if (replicateWidget)
	{
		UInvenSlotReplicateWidget* dragVisual = CreateWidget<UInvenSlotReplicateWidget>(GetWorld(), replicateWidget);
		if (dragVisual)
		{
			const FItemData* itemData = inventoryComp->itemDataMap.Find(currentSlotData.itemID);
			if (itemData)
				dragVisual->SetItemImage(itemData->itemIcon); // 아이콘 반영
			else
				dragVisual->SetItemImage(nullptr);

			dragVisual->SetVisibility(ESlateVisibility::SelfHitTestInvisible);

			dragOper->DefaultDragVisual = dragVisual;
		}
	}

	outOperation = dragOper;

}

 

NativeOnDrop함수입니다

드래그된 아이템이 슬롯 위에 놓였을때 호출되며

opration에서 드래그한 아이템의 데이터를 가져와 현재 슬롯과 교환 처리하며

드래그 비주얼과 원본 슬롯 상태를 초기화합니다

bool USlotWidget::NativeOnDrop(const FGeometry& inGeometry, const FDragDropEvent& inDragDropEvent, UDragDropOperation* inOperation)
{
	UInventoryDragDropOper* dragOper = Cast<UInventoryDragDropOper>(inOperation);
	
	if (!dragOper || !inventoryComp)
		return false;

	if (dragOper->startSlotIdx == slotIdx)
		return false;

	inventoryComp->SwapItem(dragOper->startSlotIdx, slotIdx);


	dragOper->dragSlot.Clear();
	dragOper->count = 0;
	dragOper->itemID = 0;

	SetDraggingVisual(false);
	return true;
}

 

그리고 전에 만든 슬롯을 업데이트 해주는 함수에 슬롯의 색을 초기화해주는 코드를 추가해주었습니다

void USlotWidget::UpdateSlot(const FItemSlot& inslot, const FItemData& inData)
{
	//원본
    //추가내용
    //슬롯 초기화시켜주기
	Image_ItemSlot->SetBrushFromTexture(inslot.isEmpty() ? emptyTexture : inData.itemIcon);

	float originA = 1.0f; 
	FLinearColor iconColor = Image_ItemSlot->ColorAndOpacity;
	iconColor.A = originA;
	Image_ItemSlot->SetColorAndOpacity(iconColor);

	FSlateColor textColor = TextBlock_ItemCount->ColorAndOpacity;
	FLinearColor originL = textColor.GetSpecifiedColor();
	originL.A = originA;
	TextBlock_ItemCount->SetColorAndOpacity(originL);
}

 

NativeOnDragCancelled 함수입니다

드래그 도중 슬롯밖으로 마우스를 놓거나 drop이 실패할때 원본 슬롯이 투명으로 남는 문제를 방지하기위해

안전장치 역할을 해줍니다

 

void USlotWidget::NativeOnDragCancelled(const FDragDropEvent& inDragDropEvent, UDragDropOperation* inOperation)
{
	Super::NativeOnDragCancelled(inDragDropEvent, inOperation);
	SetDraggingVisual(false);
}

 

결과

 

 

 

저작자표시 비영리 변경금지 (새창열림)

'Unreal 프로젝트 다이어리 > 두번째 프로젝트' 카테고리의 다른 글

Unreal - 인벤토리(5) ( 아이템 정보 )  (0) 2025.11.28
Unreal - 인벤토리(4) ( 정렬, 삭제 )  (0) 2025.11.26
Unreal - 인벤토리(2) ( 아이템 추가하기 )  (0) 2025.11.23
Unreal - 인벤토리(1) ( 크기변경하기, 창옮기기 )  (2) 2025.11.22
Unreal - UI (HpWidget, PostureWidget)  (0) 2025.11.21
'Unreal 프로젝트 다이어리/두번째 프로젝트' 카테고리의 다른 글
  • Unreal - 인벤토리(5) ( 아이템 정보 )
  • Unreal - 인벤토리(4) ( 정렬, 삭제 )
  • Unreal - 인벤토리(2) ( 아이템 추가하기 )
  • Unreal - 인벤토리(1) ( 크기변경하기, 창옮기기 )
lucodev
lucodev
커피와 노트북 그리고 개발
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (211) N
      • Unreal 프로젝트 다이어리 (108) N
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (35) N
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 (52)
        • Stack,Queue (7)
        • Hash (4)
        • Heap (2)
        • Sort (5)
        • Exhaustive search (5)
        • Greedy (2)
        • BFS , DFS (7)
        • Graph (2)
        • Dynamic Programming (1)
        • C++ Math (2)
        • 기타 문제 (14)
      • C++ 백준 (4)
      • C++ 팁 (1)
      • 개인 코테 & 스타디 <비공개> (29)
        • 코드 개인보관함 (9)
        • 코딩테스트+@ (11)
        • 알고리즘 스타디 (6)
        • 알고리즘 스타디 과제 (3)
        • 비공개 (0)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    언리얼 behaviortree
    unreal 시퀀스
    언리얼 파쿠르
    unreal 모션매칭
    언리얼 비헤이비어트리
    unreal 파쿠르
    unreal inventory
    언리얼 모션매칭
    언리얼 인벤토리
    언리얼 behavior tree
    Unreal Parkour
    언리얼 상호작용
    언리얼 motionmatching
    언리얼 parkour
    unreal 인벤토리
    언리얼 프로그래스바
    언리얼 ui
    언리얼
    언리얼 시퀀스
    언리얼 컷씬
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - 인벤토리(3) (드래그 앤 드롭)
상단으로

티스토리툴바