【UE4】C++の (Singlecast) Dynamic Delegate に Blueprint からバインドする

[1]:https://docs.unrealengine.com/ja/Programming/UnrealArchitecture/Delegates/index.html
[2]:https://docs.unrealengine.com/ja/Programming/UnrealArchitecture/Delegates/Dynamic/index.html

久しぶりの更新。

Blueprint のイベントディスパッチャは、Unreal C++ でいうところの Dynamic Multicast デリゲートらしい。
だが、Unreal C++ で用意する Blueprint 用のユーティリティには、Multicast は大げさすぎる局面が比較的多くある。
今回は、Multicast じゃない方のデリゲートを Blueprint からバインドする方法を見出したので、そのメモを残しておく。

- [デリゲート - UE4 公式][1]

# 自分のための復習：Unreal C++ のデリゲートに Blueprint のイベントをバインドする

Unreal C++ で用意したデリゲートを Blueprint でバインドできるようにするには、 `DECLARE_DYNAMIC_MULTICAST_DELEGATE` マクロでデリゲート型を宣言し、`UPROPERTY(BlueprintAssignable)` を指定したデリゲート変数を用意してやる。
以下は Actor Component から派生した Dynamic Delegate Component で、デリゲートの動作確認をする例。

```C++:(例)DynamicDelegateComponent.h
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "DynamicDelegateComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FBlueprintAssignableSignature);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class STATEMACHINE01_API UDynamicDelegateComponent : public UActorComponent
{
	GENERATED_BODY()
public:	
	// Sets default values for this component's properties
	UDynamicDelegateComponent();
protected:
	// Called when the game starts
	virtual void BeginPlay() override;
public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

public: // [RINDERON] properties exposed to blueprint
	UPROPERTY(BlueprintAssignable, Category = "Dynamic Delegate Component")
		FBlueprintAssignableSignature OnEventDispatcherCalled;
};
```

```C++:(例)DynamicDelegateComponent.cpp(一部)
// Called every frame
void UDynamicDelegateComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// [RINDERON]
	OnEventDispatcherCalled.Broadcast();
}
```

この後、Blueprint 側で、アクタに Dynamic Delegate Component を追加して、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/9444854f-4d5f-2c53-5fc4-72af248b4128.png)

例えば `Event BeginPlay` で以下のように組む。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/382ee810-0059-888b-eaa3-9d43cd76a991.png)

これを実行すると、`UDynamicDelegateComponent::TickComponent()` 内のデリゲートの `Broadcast()` が動いて、毎フレーム Print String が呼び出される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/5f0a6904-2635-3eda-f9d8-cb3936dd46e9.png)

# Singlecast で十分な場合

- そもそもイベントは１個しかバインドする気がない場合
- むしろ１個、もしくは０個のイベントしかバインドできないようにしたい場合
    - （知らない間にうっかり複数個バインドされてしまうと困る場合）

こういう局面は比較的多くあって、今回は Unreal C++ で用意した <font color="red"><b>Singlecast</b></font> なデリゲートを Blueprint でバインドできないか、いろいろ試してみた。
正直、できるとは思っていなかったのだが、できてしまった。

```C++:(例)DynamicDelegateComponent.h(改)
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "DynamicDelegateComponent.generated.h"

DECLARE_DYNAMIC_DELEGATE(FBlueprintCanBindThisSignature);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class STATEMACHINE01_API UDynamicDelegateComponent : public UActorComponent
{
	GENERATED_BODY()
public:	
	// Sets default values for this component's properties
	UDynamicDelegateComponent();
protected:
	// Called when the game starts
	virtual void BeginPlay() override;
public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

public: // [RINDERON] properties exposed to blueprint
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dynamic Delegate Component")
		FBlueprintCanBindThisSignature OnDelegateCalled;
};
```

```C++:(例)DynamicDelegateComponent.cpp(改／一部)
// Called every frame
void UDynamicDelegateComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// [RINDERON]
	OnDelegateCalled.ExecuteIfBound();
}
```

ポイントは２つ：

- Singlecast デリゲートを使いたいので、`DECLARE_DYNAMIC_MULTICAST_DELEGATE` ではなく、`DECLARE_DYNAMIC_DELEGATE` で宣言をする。
- デリゲート変数を `UPROPERTY(BlueprintAssignable)` ではなく、`UPROPERTY(BlueprintReadWrite)` など、普通に Blueprint に公開するプロパティのように扱ってやる。

Blueprint でのバインドの仕方は以下の通り。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/ceb1c0d7-fd65-1d8b-2b3a-269e1589e067.png)

変数にイベント(関数)をくっつける絵面が気持ち悪いような気もするが、そもそもデリゲートとはそういうものである。
実行結果は意図通り：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/3f89e22d-0397-daae-2061-5a534eabc35c.png)

# ご注意

- Dynamic デリゲートなので、関数名で検索されてから実行されるので、一定の負荷はかかる。
    - [Dynamic(動的)デリゲート - UE4公式][2] 参照。
    - どちらにせよ Dynamic なので、関数を一個呼び出すだけなら、Dynamic Multicast 版と同等程度の負荷だろう。負荷軽減の目的で使っても効果はないと思われる。
    - メリットは、デリゲート変数を Blueprint に公開できることで、何か便利に使えそうということであり、負荷軽減ではない。
- ご利用は自己責任でお願いします。
    - デリゲートを素で Blueprint に公開すること自体、Blueprint のコンセプトから外れているような気もします。(バレたら封印されるかも?　…気にしすぎかしら？)