デリゲートとは

Unreal Engine 5(UE5)でのゲーム開発において、「デリゲート(Delegate)」は非常に重要な仕組みの一つです。簡単に言うと、「特定の処理が起きたときに、別の関数を呼び出す仕組み」のこと。C++でイベント駆動型の処理を書くには、デリゲートの活用が欠かせません。
デリゲートの流れ
デリゲートが活躍する典型的なケース
ゲーム開発では「何かが起きたときに、別のオブジェクトが反応する」という設計が頻繁に登場します。
たとえば──
- プレイヤーが宝箱を開いたら、報酬を付与したい
- ボスのHPが0になったら、エンディング演出を始めたい
- ドアを開けたら、他のドアも開ける or サウンドを鳴らす
こうした 「通知」と「反応」の分離に、デリゲートは最適です。
例:宝箱を開けたことを他のクラスに通知する
① 宝箱クラスでイベントを定義(=宣言)
// MyChest.h // 引数なしのデリゲートを定義 DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnChestOpened); UCLASS() class AMyChest : public AActor { GENERATED_BODY() public: UPROPERTY(BlueprintAssignable) FOnChestOpened OnChestOpened; void Open() { UE_LOG(LogTemp, Log, TEXT("宝箱が開かれた!")); // 通知を発信 OnChestOpened.Broadcast(); } };
② ゲーム開始時に他クラスが反応関数をバインド(=BeginPlayなど)
// MyGameManager.cpp void AMyGameManager::BeginPlay() { Super::BeginPlay(); if (TargetChest) { TargetChest->OnChestOpened.AddDynamic(this, &AMyGameManager::OnChestOpenedHandler); } } void AMyGameManager::OnChestOpenedHandler() { UE_LOG(LogTemp, Log, TEXT("宝箱が開いたので報酬を与えます!")); }
③ プレイヤーなどが宝箱を開けたときにイベントを発火(=呼び出し)
// プレイヤーの操作などから宝箱を開く ChestActor->Open();
✅ この例でわかること
処理 | 説明 |
---|---|
宣言 | イベントを発信できるようにする(宝箱に通知機能を持たせる) |
バインド | 別のクラス(マネージャーなど)がそれに反応するように登録 |
発火 | 宝箱が開かれたタイミングでイベントを発信(Broadcast) |
この設計が持つ強み
- 疎結合:宝箱は「誰が聞いてるか」を気にせず開くことだけに集中
- 再利用性:同じ通知に複数のクラスが反応できる(SE、UI、報酬など)
- 柔軟性:反応側を差し替えたり、増やしたりが簡単
この中では疎結合を保ちやすいことが特に重要です。全く別のカテゴリのソースに依存関係がつくとかなり面倒なことになります。今回はあまり触れませんが
このような 典型的な通知パターンを出発点として、次は各デリゲートの種類と特徴を理解していきましょう!
デリゲートの種類
デリゲートの種類 | 用途 | 特徴 |
---|---|---|
DECLARE_DELEGATE | 通常のC++用イベント通知 | パラメータ無し / 高速 |
DECLARE_DELEGATE_OneParam | パラメータ1個あり | 型安全 |
DECLARE_DYNAMIC_DELEGATE | Blueprintでも使いたいとき | 反射に対応(遅いが便利) |
DECLARE_MULTICAST_DELEGATE | 複数の関数を同時に呼びたい | Observer的使い方 |
DECLARE_DYNAMIC_MULTICAST_DELEGATE | Blueprint&複数対応 | 最も一般的な通知イベント(例: OnClickedなど) |
1. DECLARE_DYNAMIC_MULTICAST_DELEGATE
🔹 一番よく使われる通知イベント。Blueprintと連携しやすく、複数の関数を呼び出せるのが特徴。
✅ 宣言例(MyActor.h)
// 引数なしの通知イベントを定義 DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnOpened); UCLASS() class AMyActor : public AActor { GENERATED_BODY() public: // 外部からバインド可能に UPROPERTY(BlueprintAssignable) FOnOpened OnOpened; };
✅ バインド例(他のクラスなど)
// MyActorInstance の OnOpened イベントに自分の関数を登録 MyActorInstance->OnOpened.AddDynamic(this, &UMyComponent::HandleOpened);
✅ 発火例(イベントが起きたとき)
// OnOpenedに登録された全関数を呼び出す OnOpened.Broadcast();
2. DECLARE_MULTICAST_DELEGATE
🔹 Blueprintなしで複数のC++関数を同時に呼び出したいときに便利。軽量&高速。
✅ 宣言例
DECLARE_MULTICAST_DELEGATE(FOnHealthZero); class FMyHealthSystem { public: FOnHealthZero OnHealthZero; };
✅ バインド例
HealthSystem.OnHealthZero.AddRaw(this, &MyClass::HandleDeath);
✅ 発火例
OnHealthZero.Broadcast();
3. DECLARE_DYNAMIC_DELEGATE
🔹 Blueprintから呼び出したいけど、1つの関数だけを呼ぶ用途に向いている。
✅ 宣言例
DECLARE_DYNAMIC_DELEGATE(FOnFinishFade); FOnFinishFade OnFadeComplete;
✅ バインド例
OnFadeComplete.BindDynamic(this, &UMyWidget::OnFadeFinished);
✅ 発火例
if (OnFadeComplete.IsBound()) { OnFadeComplete.Execute(); }
4. DECLARE_DELEGATE_OneParam
🔹 パラメータを渡したいときに使うC++専用の高速デリゲート。
✅ 宣言例
DECLARE_DELEGATE_OneParam(FOnDamageTaken, float); FOnDamageTaken OnDamageTaken;
✅ バインド例
OnDamageTaken.BindRaw(this, &MyClass::HandleDamage);
✅ 発火例
OnDamageTaken.ExecuteIfBound(25.0f);
5. DECLARE_DELEGATE
🔹 パラメータなし・単一関数向け。最も軽量なC++専用デリゲート。
✅ 宣言例
DECLARE_DELEGATE(FOnJump); FOnJump OnJump;
✅ バインド例
OnJump.BindRaw(this, &MyClass::DoJump);
✅ 発火例
OnJump.ExecuteIfBound();
デリゲートの際の注意点
了解です!
以下は **「UE5のデリゲート使用時に気をつけたいポイントとよくあるミス」をWordPressのブログ記事向けに、H3見出しから始まるGutenbergブロック構成でまとめた内容です。
特に「安易なゲッターによるバインド外れ」**を重点的に解説しています。
⚠️ デリゲート使用時の注意点とありがちなミス
UE5のデリゲートはとても便利ですが、使い方を誤ると思わぬバグを招くことがあります。
ここでは、デリゲート使用時に気をつけたいポイントと、ありがちな落とし穴を紹介します。
❌ よくあるミス①:ゲッター経由でコピー → バインドが外れる!
デリゲートを返す**ゲッター関数(GetXXXDelegate)**を用意している場合に、下記のような書き方をすると、思ったように関数が呼ばれないことがあります。
// よくあるNGコード FDynamicBoolDelegate LocalCopy = OtherClass->GetDelegate(); // ← 値渡しでコピー! LocalCopy.ExecuteIfBound(); // ← 実はバインドされてない!
🧠 どういうこと?
1 | FDynamicBoolDelegate |
つまり、
1 | GetDelegate() |
✅ 正しい使い方(参照で扱う or 直接呼ぶ)
// 参照で取得 FDynamicBoolDelegate& Ref = OtherClass->GetDelegate(); Ref.ExecuteIfBound(); // もしくはそのまま実体に対して呼ぶ OtherClass->GetDelegate().ExecuteIfBound();
❌ よくあるミス②:BindDynamic忘れ/AddDynamicとBindDynamicの混同
1 | DECLARE_DYNAMIC_~ |
1 | BindDynamic |
1 | AddDynamic |
しかし、
1 | BindRaw |
1 | BindLambda |
// NG:Blueprint向けのデリゲートにRawバインド MyDynamicDelegate.BindRaw(this, &MyClass::OnCalled); // ✕ // OK: MyDynamicDelegate.BindDynamic(this, &UMyClass::OnCalled); // ◯
❌ よくあるミス③:マルチキャストに 1Execute() しようとする
1 | DECLARE_DYNAMIC_MULTICAST_DELEGATE |
代わりに
1 | Broadcast() |
// NG: MyMulticast.ExecuteIfBound(); // ✕ – OK: MyMulticast.Broadcast(); // ◯
✅ 注意点まとめ
落とし穴 | 対策・コメント | ||||
---|---|---|---|---|---|
ゲッター経由のコピー | 必ず参照で受け取るか、直接呼ぶ | ||||
Blueprint向けデリゲートに Raw でバインド |
| ||||
マルチキャストに Execute() 使用 |
| ||||
|
| ||||
一度しか使わない一時デリゲートを使いまわそうとする | スコープ外になって無効化される可能性あり |
コンストラクタやBeginPlay以外でのバインドに注意
Actorがまだ無効なタイミングや、Garbage Collectionの対象になる前後でのバインドは意図しない動作を招くことがあります。
可能なら、
コメント