Unreal Engine でドラック＆ドロップできるUI (最小サンプル)

# 概要

Unreal Engine 5 でドラッグ＆ドロップできる UI を作成してみます
UE で用意されている「[Detect Drag if Pressed](https://docs.unrealengine.com/5.3/en-US/BlueprintAPI/Widget/DragAndDrop/EventReply/DetectDragifPressed/)」「On Drag Detected」「[CreateDragDropOperation](https://docs.unrealengine.com/5.3/en-US/BlueprintAPI/UserInterface/CreateDrag_DropOperation/)」「[On Drop](https://docs.unrealengine.com/5.3/en-US/API/Runtime/UMG/Blueprint/UUserWidget/OnDrop/)」などのノードを使う事でドラッグ＆ドロップを実装する事ができます

![Drag2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/37f5d425-6dc9-303f-e58a-1fbc42225f2b.gif)

## 環境
* windows 11
* Unreal Engine 5.1.1
* エディタ言語 英語

## 参考URL

以下の記事を参考させて頂きました。

https://unwitherer.blogspot.com/2017/05/umg_23.html

https://historia.co.jp/archives/6606/


# 最小サンプル

## まずはドラッグ可能な UI を作る

### 1. 新規 Widget Blueprint を作成
名前を DraggableIcon とします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/c75ef4de-6d95-f7b6-39a2-bbba0a3d3fc1.png) 

### 2. DraggableIcon をドラッグできるようにする

作成した DraggableIcon を開いて Event Graph を編集します
* FUNCTIONS の Override をクリック
* 出てきたウィンドウから **On Mouse Button Down** を検索して追加 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/b49d4146-a095-a582-1069-0a3d995a9736.png)

On Mouse Button Down を開いて以下のようにノードを接続します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/24685b54-6430-a895-ff0f-c536ee13b7ba.png)

* 再び FUNCTIONS の Override をクリック
* 出てきたウィンドウから **On Drag Detected** を検索して追加 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/1e127873-3e01-d4d4-ebb9-75cc4c506dfa.png)

On Drag Detected を開いて以下のようにノードを接続します
これだけでドラッグの機能は完成です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/508f0850-0db0-39b3-f4df-6ce09e851b96.png)

### 3. DraggableIcon の見た目を作成

DraggableIcon の Designer を開きます

* 左下の Hierarchy に「Canvas Panel」と「Image」を追加
* 追加した Image を選択して、右側の Details から以下の様に変更する
  * Position X と Position Y を 100.0
  * Size X と Size Y を 200.0
  * Color を 青に

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/aa8956b2-d2c9-59cb-fab6-07357a33cc10.png)


### 4. DraggableIcon を表示する

レベルブループリントから DraggableIcon を表示させます

* World に戻りレベルブループリントを開く
* 以下のようにノードを接続する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/e0535c5d-1251-195e-bc3d-cf5449334edc.png)

### 5. 実行

Alt + P などから Play をします
青いアイコンが表示され、そのアイコンをドラッグする事ができます

![Drag2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/96bc6da3-494b-70a1-e8c8-fadfc3fa2978.gif)


## ドロップ可能アイコンを作成

次はドラッグしたアイコンをドロップする場所を作成します

### 1. 新規 Widget Blueprint を作成
名前を DroppableIcon とします

### 2. DroppableIcon にドロップできるようにする

作成した DroppableIcon を開いて Event Graph を編集します
* FUNCTIONS の Override をクリック
* 出てきたウィンドウから **[On Drop](https://docs.unrealengine.com/5.3/en-US/API/Runtime/UMG/Blueprint/UUserWidget/OnDrop/)** を検索して追加 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/518a1627-6802-dd2e-2e8c-889fcebdd016.png)

On Drop を開いて以下のようにノードを接続します
ここでは単にドロップされたら文字を表示するようにします

:::note warn
Return Node の Return Value を **True** にします。ここが False のままだとドロップした場合も DraggableIcon で Event On Drag Cancelled が呼ばれてしまいます
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/eb9287a4-c86f-496f-3e2c-e73631199984.png)

### 3. DroppableIcon の見た目を作成

DroppableIcon の Designer を開きます
見た目の作成は DraggableIcon と同じで、色だけ青ではなくピンクにします

### 4. DraggableIcon と DroppableIcon を同時に表示する

* 新規 Widget Blueprint を作成
* Designer を開く
* 左下の Hierarchy に「Grid Panel」を追加
    * Column Fill を２つ追加 (Index[0] = 0.5, Index[1] = 0.5)
    * Row Fill を１つ追加 (Index[0] = 1.0)
* 「Grid Panel」に「Named Slot」を２つ追加
    * 片方の「Named Slot」の Slot(Grid Slot) の Column を 1 に
*  それぞれの「Named Slot」に「DraggableIcon」と「DroppableIcon」を追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/c7558951-db7c-20b6-2f24-12f4cf056fbc.png)

レベルブループリントから表示させる Widget を変更する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/2d11bc38-14df-3d80-0595-6d20b576ea66.png)


### 5. 実行

Alt + P などから Play をします
青アイコンをピンクアイコンへドラッグ＆ドロップすると Hello の文字が表示されます

![Drag2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/37f5d425-6dc9-303f-e58a-1fbc42225f2b.gif)


# 発展

## ドラッグ元からドロップ先へ情報を伝える

[Create Drag & Drop Operationノード](https://docs.unrealengine.com/5.3/en-US/BlueprintAPI/UserInterface/CreateDrag_DropOperation/)を使う事でドラッグ元からドロップ先へ情報を伝える事が出来ます。

### 1. DraggableIcon の Event Graph を編集

Create Drag & Drop Operationノード の Tag 文字を変更します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/f46489e1-d429-e644-dae7-b222e43a46bd.png)

* **Class** ... Drag Drop Operation を継承したクラスを自身で作成している場合は、ここから選択出来る
* **Tag** ... Drop先へ文字列を渡せる
* **Payload** ... Drop先へ UObject を渡せる
* **Default Drag Visual** ... ドラッグ中の見た目
* **Pivot** ... ドラッグ中のUIの位置を調整
* **Offset** ... ドラッグ中のUIの位置を調整


### 2. DroppableIcon の Event Graph を編集

[On Drop](https://docs.unrealengine.com/5.3/en-US/API/Runtime/UMG/Blueprint/UUserWidget/OnDrop/) を以下のように変更します

:::note info
On Drop の Operation ピンから Drag & Drop Operation ノードの内容を取得する事ができます。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/15d703bc-3eb6-db53-941b-3e1b7ad05653.png)


### 3. 実行

これで実行すると DraggableIcon の Create Drag & Drop Operation で設定した Tag 文字が表示されるようになります




## その他のドラッグノード

* **On Drag Cancelled** ... ドラッグしたけどドロップしなかった場合に呼ばれる
* **On Drag Enter** ... ドラッグしたアイコンが自身のUIに重なった瞬間に呼ばれる
* **On Drag Leave** ... ドラッグしたアイコンが自身のUIから離れた瞬間に呼ばれる
* **On Drag Over** ... ドラッグしたアイコンが自身のUIに重なっている間呼ばれる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39286/508aab36-b961-e7f3-d489-6e3452d700a6.png)


## ドラッグ＆ドロップでアイコンを移動

こちらのブログ記事にとても分かりやすくまとまっています

* ドラッグ開始したらアイコンを消す
* ドラッグキャンセルしたらアイコンを戻す
* ドラッグ元から [CreateDrag & DropOperationノード](https://docs.unrealengine.com/5.3/en-US/BlueprintAPI/UserInterface/CreateDrag_DropOperation/) の Payload でドロップ先にアイコン(UObject) を渡す
* On Drop の Operation ピンから上記のアイコン(UObject)を受け取りドロップ先へ追加

https://unwitherer.blogspot.com/2017/05/umg_23.html

## ドラッグ中のアイコンを半透明に

こちらのブログ記事にとても分かりやすくまとまっています
DragDropOperation を継承したクラスの利用方法についてもまとまっています
 
https://historia.co.jp/archives/6606/