LoginSignup
3
3

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-07-05

久しぶりの更新。

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

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

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

(例)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;
};
(例)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

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

image.png

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

image.png

Singlecast で十分な場合

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

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

(例)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;
};
(例)DynamicDelegateComponent.cpp(改/一部)
// Called every frame
void UDynamicDelegateComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

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

ポイントは2つ:

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

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

image.png

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

image.png

ご注意

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3