タイトル: どこからでも呼び出せるカスタムイベントを作成する方法
SEOタイトル: UE5 グローバル カスタム イベント作成完全ガイド(GameInstance/Subsystem/Event Dispatcher)
| この記事の要点 |
|
「どこからでも呼べる」の意味
UE5 で「Blueprint からどこからでも呼び出せるカスタムイベント」を作りたい場合、その本質はグローバルな置き場(シングルトン)を確保することです。レベル(マップ)が切り替わるたびに破棄されない場所に、イベントの発信源を置きます。
| 置き場 | 寿命 | 用途 |
|---|---|---|
| GameInstance | ゲーム起動〜終了 | レベル跨ぎグローバル(推奨) |
| GameInstanceSubsystem | ゲーム起動〜終了 | 機能別分割(モダン推奨) |
| GameState | レベル切替で破棄 | マップ内グローバル |
| GameMode | レベル切替で破棄(サーバのみ) | ルール定義 |
| PlayerController | プレイヤー単位 | 入力・UI 制御 |
| 個別 Actor | そのレベルのみ | ローカル機能 |
方法1: GameInstance に Event Dispatcher を置く
最も古典的で確実な方法です。次の手順で進めます。
- Content Browser → 右クリック → Blueprint Class → Game Instance を継承 →
BP_MyGameInstance - Project Settings → Maps & Modes → Game Instance Class を
BP_MyGameInstanceに変更 BP_MyGameInstanceを開き、Event Dispatchers ペインでOnEnemyDefeated等を追加- イベント発信側:
Get Game Instance→Cast To BP_MyGameInstance→Call OnEnemyDefeated - イベント受信側: 同様に Cast →
Bind Event to OnEnemyDefeated→ カスタムイベントに接続
[Enemy_BP] [HUD_BP]
↓ Defeated ↓ BeginPlay
Get Game Instance Get Game Instance
↓ ↓
Cast To BP_MyGameInstance Cast To BP_MyGameInstance
↓ ↓
Call OnEnemyDefeated Bind Event to OnEnemyDefeated
↓
Custom Event: UpdateScore
方法2: GameInstanceSubsystem(推奨・モダン)
UE 4.22+ で導入された UGameInstanceSubsystem は、GameInstance を肥大化させずに機能ごとに分離できるモダンな仕組みです。Blueprint からは Get Game Instance Subsystem (BP_QuestSubsystem) でいきなり取れるため、Cast 不要でアクセスできます。
// MyQuestSubsystem.h
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "MyQuestSubsystem.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnQuestCompleted, FName, QuestId);
UCLASS()
class MYGAME_API UMyQuestSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable, Category="Quest")
FOnQuestCompleted OnQuestCompleted;
UFUNCTION(BlueprintCallable, Category="Quest")
void CompleteQuest(FName QuestId)
{
OnQuestCompleted.Broadcast(QuestId);
}
};
Blueprint からは以下のように使えます。
[発信側]
Get Game Instance Subsystem (MyQuestSubsystem)
→ Complete Quest (QuestId="DragonSlain")
[受信側 - BeginPlay 等で]
Get Game Instance Subsystem (MyQuestSubsystem)
→ Bind Event to On Quest Completed
→ Custom Event handler でクエスト UI 更新
方法3: Blueprint Interface
「呼び方の契約」だけ共有したい場合は Blueprint Interface を使います。シングルトンとは異なり、対象 Actor が分かっているケースで利用します。
- Content Browser → Blueprint Interface →
BPI_Damageable作成 - Function:
ReceiveDamage(int32 Amount)を追加 - 各 Actor の Class Settings → Interfaces → Add で
BPI_Damageableを実装 - 呼ぶ側:
Receive Damage (Message)ノードで、Target に Actor を渡す
方法4: シーン跨ぎの永続データ
イベントだけでなく値も保持したいなら、GameInstance のメンバ変数(Save Game との連携も)を使います。
| 用途 | 置き場 | 備考 |
|---|---|---|
| レベル間のスコア/所持金 | GameInstance 変数 | メモリ上のみ。閉じると消える |
| セーブデータ | SaveGame オブジェクト | ファイル書き込み |
| ステージ間の進捗 | GameInstance + SaveGame | 両立 |
| ネットワーク同期データ | GameState / Replicated | マルチプレイ向け |
レベル間通信のフロー例
Level_Field(フィールドマップ)
Player が敵に勝利
→ GameInstance.OnVictory(EnemyId, Reward) を呼ぶ
→ GameInstance に Reward を保存
→ Open Level "Level_Result"
Level_Result(リザルト画面)
BeginPlay
→ Get Game Instance.GetReward() で値取得
→ UI に表示
注意点と落とし穴
- GameInstance クラスを設定し忘れると、いくら Blueprint を作っても使われない(Project Settings 必須)
- Subsystem は引数なしの Initialize しか持てない。データは
Initialize内で別から取得 - Event Dispatcher の Bind は重複防止のために Unbind を意識。EndPlay で Unbind All を推奨
- Actor が破棄された後でも Bind が残るとクラッシュリスク。Weak Reference / EndPlay で確実に解除
- マルチプレイ環境では、GameInstance はクライアント/サーバそれぞれにあるため、同期は別途 Replication 設計が必要
C++ から Multicast Delegate を公開する
// マルチキャストデリゲートで Blueprint からも Bind 可能に
UCLASS(Blueprintable)
class UMyEventBus : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPause);
UPROPERTY(BlueprintAssignable) FOnPause OnPause;
UFUNCTION(BlueprintCallable) void Pause() { OnPause.Broadcast(); }
};
FAQ
Q: GameInstance と Subsystem、どちらを使うべき?
A: 新規プロジェクトは Subsystem。GameInstance を肥大化させず機能ごとに分離できます。既存プロジェクトの拡張なら GameInstance に追加で問題なし。
Q: PlayerController に置くのとどう違う?
A: PlayerController はプレイヤー単位。ローカルマルチでは複数生成され、レベル切替で破棄されます。ゲーム全体のイベントには不向き。
Q: Bind がリークしたとき?
A: 破棄済 Actor のハンドラに Broadcast すると Access None / クラッシュの原因になります。Actor の EndPlay で Unbind を呼ぶ習慣を。