ue-blueprint-cpp-interop について
UE 5.8 の C++ と Blueprint の連携を扱う開発スキルです。リフレクション指定子によるノード構成や、ネイティブコードから Blueprint にデータ、処理、イベントを公開する方法を説明します。
主な機能
- 01UFUNCTION のノードとイベント設定
- 02UPROPERTY のデータ公開規則
- 03関数ライブラリと非同期ノードの実装パターン
- 04Blueprint インターフェースとデリゲートの処理
- 05ネイティブコードからの Blueprint 呼び出し
活用シーン
- 01C++ 関数を Blueprint から呼び出し・オーバーライド
- 02プロパティの Blueprint 読み書き設定
- 03遅延または非同期 Blueprint ノードの実装
- 04ネイティブコードから Blueprint ロジックを実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ quodsoler/ unreal-engine-skills --skill ue-blueprint-cpp-interopインストール後、Claude Code で/ue-blueprint-cpp-interopを入力して読み込まれたか確認します。
同梱ファイルreferences/blueprint-meta-specifiers.mdreferences/blueprint-node-patterns.md
詳細
UE Blueprint / C++ 相互運用
対象エンジン:UE 5.8。以下の API は 5.8 のヘッダーで検証済みです。古い形式は「非推奨 — 使用しないでください」に記載しています。
このスキルでは、ネイティブコードと Blueprint VM の境界を扱います。どの UFUNCTION/UPROPERTY 指定子と meta= キーがどのノード形状を生成するか、関数ライブラリ、潜在ノードと非同期ノード、Blueprint で実装可能なインターフェース、C++ から Blueprint グラフを呼び出す方法を説明します。ここで扱うものはすべて Core、CoreUObject、Engine に含まれます(PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });)。プロジェクト設定のページには DeveloperSettings も必要です。すべての指定子の根拠となるのは Runtime/CoreUObject/Public/UObject/ObjectMacros.h です。UC、UI、UF、UP、US、UM の列挙型で宣言されていないものは指定子ではありません。
コンテキスト
.agents/ue-project-context.md があれば読み込みます(モジュール名、規約、有効なプラグイン、GAS/ネットワーク設定)。ファイルがなくても作業を中断しないでください。
依頼内容とコードベースから該当する領域を特定します。複数の解釈が考えられ、それによってコードが異なる場合にのみ質問してください。
| 依頼内容 | 参照先 |
|---|---|
| Blueprint から呼び出し可能、またはオーバーライド可能な C++ 関数を作成する | UFUNCTION Exposure |
| Blueprint でデータを表示または編集する、ゲッター/セッター | UPROPERTY Exposure |
静的ヘルパー、WorldContext、DefaultToSelf | Function Libraries |
| 後から完了する実行ピンを持つノード(Delay 形式) | Latent Nodes |
| イベント発生時に実行される複数の出力実行ピンを持つノード | Async Action Nodes |
Blueprint で実装できるインターフェース、Execute_、TScriptInterface | Blueprint Interfaces |
Blueprint の型としての UENUM、USTRUCT、コンテナ | Enums and Structs in Blueprint |
BlueprintAssignable イベント、C++ デリゲートへの Blueprint のバインド | Delegates and Events |
| ネイティブコードから Blueprint のロジックを実行する、Blueprint クラス | Calling Blueprint from Native Code |
サブシステム、UDeveloperSettings、Exec コマンド | Subsystems and Settings in Blueprint |
| Details パネルのボタン、エディター専用アクション | Editor-Callable Functions |
UFUNCTION の公開
| 指定子 | ノードの形状 | C++ 本体 |
|---|---|---|
BlueprintCallable | 実行ピンの入力と出力あり | 自分で実装 |
BlueprintPure | 実行ピンなし。BlueprintCallable を暗黙に含みます | 自分で実装、副作用なし |
BlueprintImplementableEvent | Blueprint が実装するイベント | なし — UHT がサンクを生成します |
BlueprintNativeEvent | Blueprint がオーバーライドできるイベント | Name_Implementation のみ |
BlueprintGetter / BlueprintSetter | 非表示。プロパティ経由で呼び出します | 自分で実装 |
BlueprintAuthorityOnly | ネットワーク権限がない場合、Blueprint からの呼び出しはスキップされます(C++ から直接呼び出した場合は実行されます) | 自分で実装 |
BlueprintCosmetic | 専用サーバーでは Blueprint からの呼び出しはスキップされます(C++ から直接呼び出した場合は実行されます) | 自分で実装 |
BlueprintInternalUseOnly | パレットには表示されず、生成されたノードのみが呼び出します | 自分で実装 |
CallInEditor | 詳細パネルのボタン | 自分で実装 |
Exec | コンソールコマンド | 自分で実装 |
Category="A\|B" は、ネストされたパレットカテゴリを作成します。ノードの形状を決める meta= キー(DisplayName、ToolTip、Keywords、CompactNodeTitle、AdvancedDisplay、ReturnDisplayName、HidePin、DeterminesOutputType、DynamicOutputParam、ArrayParm、ExpandEnumAsExecs、WorldContext、UnsafeDuringActorConstruction、DevelopmentOnly、BlueprintThreadSafe など)は、ヘッダーの引用元とともにreferences/blueprint-meta-specifiers.mdに一覧されています。
// MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS(Blueprintable)
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="MyGame|Combat", meta=(Keywords="damage hurt"))
void ApplyDamage(float Amount);
UFUNCTION(BlueprintPure, Category="MyGame|Combat", meta=(CompactNodeTitle="HP", ReturnDisplayName="Health"))
float GetHealth() const;
/** Blueprint supplies the whole body; C++ never defines this. */
UFUNCTION(BlueprintImplementableEvent, Category="MyGame|Combat")
void OnDamaged(float Amount);
/** C++ supplies the default in OnDied_Implementation; Blueprint may override it. */
UFUNCTION(BlueprintNativeEvent, Category="MyGame|Combat")
void OnDied();
virtual void OnDied_Implementation();
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="MyGame|Combat")
void ResetOnServer() { Health = MaxHealth; } // Blueprint calls skipped on clients
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="MyGame|FX")
void PlayHitFlash() {} // Blueprint calls skipped on a dedicated server
UFUNCTION(CallInEditor, Category="MyGame|Tools")
void SnapToGround() {} // button in the Details panel
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="MyGame|Combat", meta=(AllowPrivateAccess="true", ClampMin="0.0"))
float Health = 100.f;
float MaxHealth = 100.f;
};
// MyActor.cpp
#include "MyActor.h"
void AMyActor::ApplyDamage(float Amount)
{
Health = FMath::Max(0.f, Health - Amount);
OnDamaged(Amount); // runs the Blueprint graph
if (Health <= 0.f) { OnDied(); } // runs the BP override if any, else OnDied_Implementation
}
float AMyActor::GetHealth() const { return Health; }
void AMyActor::OnDied_Implementation() {} // the C++ default, overridable in Blueprint
イベントを発生させるときは、OnDied() のように通常の名前で呼び出し、OnDied_Implementation() は呼び出さないでください。通常の名前は、Blueprint にディスパッチする生成済みサンクです。サブクラスでは virtual void OnDied_Implementation() override; をオーバーライドし、Super::OnDied_Implementation(); でチェーンします。Super::OnDied(); は呼び出さないでください。
パラメーターとピン
| C++ パラメーター | Blueprint ピン |
|---|---|
float Amount | 入力 |
const FVector& Base | 入力、参照渡し |
FVector& Out | 出力ピンであり、入力ではありません |
UPARAM(ref) FVector& InOut | 入力であり、出力でもある参照渡しの値 |
UPARAM(DisplayName="Event") FMyReadySignature Callback | ノード上で名前が変更された入力 |
単独の T& には、UHT によって OutParm フラグが付与されます。UPARAM(ref) は ReferenceParm を追加するため、ピンは入力のままになります。meta=(AutoCreateRefTerm="Offset") を指定すると、参照入力に何も接続されていない場合、インラインリテラルが用意されます。
UPROPERTY の公開
| 指定子 | Blueprint での効果 |
|---|---|
BlueprintReadWrite | Get ノードと Set ノード |
BlueprintReadOnly | Get ノードのみ |
BlueprintGetter=Fn | Get は UFUNCTION(BlueprintGetter) を経由します |
BlueprintSetter=Fn | Set は UFUNCTION(BlueprintSetter) を経由します。BlueprintReadWrite も暗黙的に指定されます |
BlueprintAssignable | Bind Event ノード(マルチキャスト動的デリゲートのみ) |
BlueprintCallable | Broadcast ノード(マルチキャスト動的デリゲートのみ) |
BlueprintAuthorityOnly | デリゲートが受け付けるのは BlueprintAuthorityOnly イベントのみです |
private メンバーに BlueprintReadWrite/BlueprintReadOnly を指定すると、プロパティに meta=(AllowPrivateAccess="true") が付いていない限り、UHT エラー(「BlueprintReadWrite should not be used on private members」)になります。エディター専用プロパティは、Blueprint に公開する構造体メンバーにはできません。エディターの meta= キー(ClampMin/ClampMax、UIMin/UIMax、EditCondition、EditConditionHides、InlineEditConditionToggle、TitleProperty、ShowOnlyInnerProperties、MultiLine、GetOptions、AllowedClasses、MustImplement、Categories、Bitmask/BitmaskEnum、ExposeOnSpawn):references/blueprint-meta-specifiers.md。
| C++ メンバー型 | Blueprint ピン |
|---|---|
double/float | Real |
TObjectPtr<UStaticMesh> | オブジェクト参照 |
TSubclassOf<AActor> | クラス(meta=(MustImplement=…)、AllowedClasses、BlueprintBaseOnly でフィルタリング) |
TSoftObjectPtr<T>/TSoftClassPtr<T> | ソフト参照。Blueprint が必要に応じて解決またはロードします |
FInstancedStruct | エディターで具象型を選択する構造体ピン |
TScriptInterface<IMyInteractable> | インターフェース参照 |
FMyHealthChangedSignature(マルチキャスト動的) | BlueprintAssignable による Bind Event/Broadcast ノード |
FTimerHandle | そのまま渡される USTRUCT(BlueprintType) ハンドル |
ExposeOnSpawn、EditCondition/EditConditionHides、InlineEditConditionToggle、MustImplement、BlueprintGetter/BlueprintSetter のペアを示すコンポーネントの実例:references/blueprint-meta-specifiers.md。
Float と double。 float と double のプロパティは、どちらも Blueprint の Real ピンとして表示されます(UEdGraphSchema_K2 は FFloatProperty と FDoubleProperty を、サブカテゴリが PC_Float/PC_Double の PC_Real にマッピングします)。また、Blueprint で定義された変数は double です。Blueprint の数式処理に渡すスカラーには double を宣言し、縮小変換が挿入されないようにしてください。float のままにするのは、エンジン側の型がすでに float の場合だけです。
関数ライブラリ
UBlueprintFunctionLibrary(Kismet/BlueprintFunctionLibrary.h)は UCLASS(Abstract) で、すべてのメンバーが static です。CDO 上では GetWorld() が null を返すため、const UObject* WorldContextObject を受け取り、meta=(WorldContext="WorldContextObject") を指定して、GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull) で解決してください。meta=(DefaultToSelf="Param") を指定すると、ピンが呼び出し元のオブジェクトにあらかじめ接続されます。
// MyBlueprintLibrary.h
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Templates/SubclassOf.h"
#include "MyBlueprintLibrary.generated.h"
class AActor;
UENUM(BlueprintType)
enum class EMyConsumeResult : uint8
{
Consumed,
NotEnough
};
UCLASS()
class MYGAME_API UMyBlueprintLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/** WorldContextObject is hidden on the node and filled in by the graph. */
UFUNCTION(BlueprintCallable, Category="MyGame|Utility", meta=(WorldContext="WorldContextObject"))
static int32 CountPawns(const UObject* WorldContextObject);
/** The return pin takes the type plugged into ActorClass, so Blueprint needs no cast. */
UFUNCTION(BlueprintPure, Category="MyGame|Utility", meta=(DefaultToSelf="Target", DeterminesOutputType="ActorClass"))
static AActor* FindAttachedActorOfClass(AActor* Target, TSubclassOf<AActor> ActorClass);
/** One input enum becomes one output exec pin per enumerator. */
UFUNCTION(BlueprintCallable, Category="MyGame|Utility", meta=(ExpandEnumAsExecs="Result"))
static void TryConsume(int32 Available, int32 Amount, EMyConsumeResult& Result);
};
対応する .cpp:references/blueprint-node-patterns.md。ExpandEnumAsExecs が受け付ける入力パラメーターはちょうど 1 つです(2 つ目を指定すると UHT エラーになります)。戻り値を展開するには ReturnValue という名前を付け、bool には ExpandBoolAsExecs を使用してください。ワイルドカード配列ノードでは meta=(ArrayParm="Items", ArrayTypeDependentParams="Item") を使用します。
潜在ノード
潜在ノードは、1 つの実行ピンをフレーム間で保留します。meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject") と、末尾の FLatentActionInfo パラメーターが必要です。また、FPendingLatentAction のサブクラスを作成し、ワールドの FLatentActionManager に登録します。エンジンでの参考実装は UKismetSystemLibrary::Delay と FDelayAction(Engine/Public/DelayAction.h)です。
// MyLatentLibrary.h — declaration
UFUNCTION(BlueprintCallable, Category="MyGame|Flow", meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject", Duration="1.0"))
static void WaitSeconds(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo);
// MyLatentLibrary.cpp — the UUID guard is mandatory
void UMyLatentLibrary::WaitSeconds(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
FLatentActionManager& Manager = World->GetLatentActionManager();
if (Manager.FindExistingAction<FMyWaitAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr)
{
Manager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FMyWaitAction(Duration, LatentInfo));
}
}
}
FindExistingAction ガードがないと、ノードへの再入時に同じ UUID で 2 つ目のアクションが積まれ、実行ピンが複数回発火します。アクションのサブクラスでは UpdateOperation(FLatentResponse& Response) をオーバーライドし、Response.FinishAndTriggerIf(bDone, ExecutionFunction, OutputLink, CallbackTarget) で処理を完了します。コンストラクターでは FLatentActionInfo から ExecutionFunction、Linkage、CallbackTarget をコピーします。また、NotifyObjectDestroyed()、NotifyActionAborted()、および WITH_EDITOR の場合は GetDescription() const もオーバーライドします。複数の終了リンクには、FLatentResponse が DoneIf(bool) と TriggerLink(ExecutionFunction, LinkID, CallbackTarget) も提供します。サブクラスの完全な実装と、その他の FLatentActionManager API については、references/blueprint-node-patterns.md を参照してください。
非同期アクションノード
UBlueprintAsyncActionBase(Kismet/BlueprintAsyncActionBase.h)を使うと、実行入力ピンが 1 つ、BlueprintAssignable デリゲートごとに実行出力ピンが 1 つあるノードを作成できます。生成されたノードだけが呼び出せるよう、静的ファクトリーには meta=(BlueprintInternalUseOnly="true") を指定する必要があります。
// MyWaitForHealthAction.h
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "MyWaitForHealthAction.generated.h"
class UMyStatsComponent;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMyHealthThresholdSignature, double, Health);
UCLASS()
class MYGAME_API UMyWaitForHealthAction : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="MyGame|Async", meta=(BlueprintInternalUseOnly="true", WorldContext="WorldContextObject", DisplayName="Wait For Health Below"))
static UMyWaitForHealthAction* WaitForHealthBelow(UObject* WorldContextObject, UMyStatsComponent* Stats, double Threshold);
virtual void Activate() override;
UPROPERTY(BlueprintAssignable)
FMyHealthThresholdSignature OnReached; // one output exec pin
UPROPERTY(BlueprintAssignable)
FMyHealthThresholdSignature OnFailed; // a second output exec pin
private:
UFUNCTION()
void HandleHealthChanged(double NewHealth); // AddDynamic targets must be UFUNCTIONs
UPROPERTY()
TObjectPtr<UMyStatsComponent> TrackedStats;
double ThresholdValue = 0.0;
};
ファクトリーでは NewObject<UMyWaitForHealthAction>() を呼び出して入力を保存し、RegisterWithGameInstance(WorldContextObject) を呼び出してからアクションを返します。ノードはその後、デリゲートをバインドして Activate() を呼び出し、そこで処理を開始します。各完了経路では、1 回だけブロードキャストして SetReadyToDestroy() を呼び出します。登録されていないアクションは、作成されたフレームの間だけ存在します(RF_StrongRefOnFrame)。そのため、後からデリゲートが発火しても、アクションはすでにガベージコレクションされています。bp.MaxAsyncActionCount(デフォルトは 10000)を超えるアクションが同時に存在する場合、エンジンが警告します。
UCancellableAsyncAction(Engine/CancellableAsyncAction.h、UCLASS(Abstract, BlueprintType, meta=(ExposedAsyncProxy=AsyncAction)))は、Cancel()、IsActive() const、ShouldBroadcastDelegates() const を追加するため、ノードは後からキャンセルできるようオブジェクトを返します。すべてのブロードキャストを ShouldBroadcastDelegates() でガードしてください。Activate/Cancel の完全な実装については、references/blueprint-node-patterns.md を参照してください。
Blueprint インターフェース
UINTERFACE 自体の指定子(UI::)は MinimalAPI、Blueprintable、NotBlueprintable、ConversionRoot と meta= です。UHT 共通の BlueprintType も使用でき、エンジンのインターフェースでは、Blueprint 変数型としてインターフェースを使用できるようにこれを指定しています。Blueprint から実装できるメンバーは BlueprintImplementableEvent と BlueprintNativeEvent です。通常の virtual C++ メソッドは Blueprint からは見えません。
// MyInteractable.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "MyInteractable.generated.h"
class AActor;
UINTERFACE(Blueprintable, BlueprintType, MinimalAPI)
class UMyInteractable : public UInterface
{
GENERATED_BODY()
};
class MYGAME_API IMyInteractable
{
GENERATED_BODY()
public:
/** Blueprint-only implementations are allowed; C++ implementers write Interact_Implementation. */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="MyGame|Interaction")
bool Interact(AActor* Interactor);
virtual bool Interact_Implementation(AActor* Interactor);
virtual float GetInteractRange() const { return 200.f; } // native-only: invisible to Blueprint
};
// Calling an interface that may be implemented in C++ or in Blueprint
bool MyTryInteract(UObject* Target, AActor* Interactor)
{
return Target && Target->Implements<UMyInteractable>()
&& IMyInteractable::Execute_Interact(Target, Interactor);
}
| 形式 | C++ の実装 | Blueprint の実装 |
|---|---|---|
IMyInteractable::Execute_Interact(Obj, …) | はい | はい — 常にこれを使用 |
Obj->Implements<UMyInteractable>() | はい | はい |
Obj->GetClass()->ImplementsInterface(UMyInteractable::StaticClass()) | はい | はい |
Cast<IMyInteractable>(Obj) の後に直接呼び出す | はい | いいえ — キャストは null を返します |
TScriptInterface<IMyInteractable> メンバー | はい | インターフェースポインターは null です。それでも Execute_ 経由で呼び出してください |
TScriptInterface<T>(UObject/ScriptInterface.h)はオブジェクトとインターフェースポインターを一緒に保持し、ネイティブインターフェース専用として有用であるとドキュメントに記載されています。デザイナーが絞り込み済みのピッカーを使えるよう、UPROPERTY(EditAnywhere, BlueprintReadWrite) TScriptInterface<IMyInteractable> Target; を宣言し、呼び出しには引き続き Execute_ を使用してください。
Blueprint の列挙型と構造体
// MyTypes.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "MyTypes.generated.h"
UENUM(BlueprintType)
enum class EMyWeaponState : uint8 // BlueprintType enums must be uint8-based
{
Idle,
Firing UMETA(DisplayName="Firing Weapon"),
Reloading,
MAX UMETA(Hidden)
};
USTRUCT(BlueprintType)
struct MYGAME_API FMyWeaponStats
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
double BaseDamage = 10.0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
TArray<FName> Tags; // container of a Blueprint-supported type
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
TMap<FName, double> Modifiers; // key and value must both be Blueprint-supported
};
USTRUCT(BlueprintType)
struct MYGAME_API FMyWeaponRow : public FTableRowBase // data table row type
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
FMyWeaponStats Stats;
};
UENUM(BlueprintType)にはenum class : uint8が必要です。UHT はそれ以外の基底型を拒否します(「Invalid BlueprintType enum base - currently only uint8 supported」)。UMETA(DisplayName="…")は列挙子の表示名を変更し、UMETA(Hidden)はピッカーに表示されないようにします。USTRUCT(BlueprintType)を指定すると、Make ノードと Break ノードが使えるようになります。構造体にはUFUNCTIONを含められません。構造体のヘルパー関数は関数ライブラリに配置してください。- コンテナーのネストはできません。 UHT では、
TArray、TSet、TMapがそれぞれの「コンテナーのキー/値にできる」機能を無効にするため、TArray<TArray<int32>>とTMap<FName, TArray<int32>>はコンパイルできません。内側のコンテナーはUSTRUCTでラップしてください。 - コンテナーを Blueprint に公開できるのは、要素型が Blueprint に対応している場合のみです。
TMapではキー型も Blueprint に対応している必要があります。 FTableRowBase(Engine/DataTable.h)はUSTRUCT(BlueprintInternalUseOnly)です。行の構造体はこれを継承し、派生構造体にBlueprintTypeを指定してください。テーブルの読み込みと行の検索については、ue-data-assets-tablesを参照してください。FInstancedStruct(StructUtils/InstancedStruct.h)はUSTRUCT(BlueprintType)であり、エディターで具体的な構造体型を選択できる単一のピンを Blueprint に提供します。TInstancedStruct<FMyBase>は型付きの C++ ラッパーです。
デリゲートとイベント
Blueprint の境界を越えられるのはダイナミックデリゲートのみです。宣言マクロとネイティブバインドのルールについては、ue-cpp-foundations を参照してください。
- マルチキャストのダイナミックデリゲートに
UPROPERTY(BlueprintAssignable)を指定すると、Blueprint に Bind Event ノードが追加されます。さらにBlueprintCallableを指定すると、Broadcast ノードも追加されます。どちらもマルチキャストのダイナミックデリゲートでのみ有効です。 - デリゲートのパラメーターには名前が必要です。イベントノードのピン名として使用されます。
AddDynamicでバインドする C++ ハンドラーにはUFUNCTION()が必要です。そうでない場合、実行時の名前検索に失敗し、ハンドラーは実行されません。- 単一のダイナミックデリゲート(
DECLARE_DYNAMIC_DELEGATE、DECLARE_DYNAMIC_DELEGATE_OneParam、…)はUFUNCTIONのパラメーターとして使用できます。これにより、非同期ノードでワンショットのコールバックを受け取れます。例:UPARAM(DisplayName="Event") FMyReadySignature Callback。 - ネイティブ(非ダイナミック)デリゲートは一切公開できません。ダイナミックデリゲートまたは非同期アクションでラップしてください。
ネイティブコードから Blueprint を呼び出す
| 必要なもの | 使用するもの |
|---|---|
| デザイナーが実装するフック | UFUNCTION(BlueprintImplementableEvent)。通常の名前で呼び出します |
| C++ のデフォルト実装を持つフック | UFUNCTION(BlueprintNativeEvent)。通常の名前で呼び出します |
| 複数のグラフがリッスンするイベントを発火する | UPROPERTY(BlueprintAssignable) のマルチキャストデリゲート、Broadcast(...) |
| Blueprint アセットにのみ存在する関数を呼び出す | FindFunction + ProcessEvent |
| Blueprint クラスからデフォルト値を読み取る | TSubclassOf<T>::GetDefaultObject()、UClass::GetDefaultObject<T>() |
// The params struct must match the function's parameter list exactly, in declaration order.
struct FMyOnScoredParams
{
int32 Points;
FString Reason;
};
void MyNotifyScored(UObject* Target, int32 Points)
{
if (!Target) { return; }
if (UFunction* Func = Target->FindFunction(FName(TEXT("OnScored"))))
{
checkf(Func->ParmsSize == sizeof(FMyOnScoredParams), TEXT("OnScored signature changed"));
FMyOnScoredParams Params;
Params.Points = Points;
Params.Reason = TEXT("Kill");
Target->ProcessEvent(Func, &Params);
}
}
Blueprint の名前が変更された場合や再コンパイルで削除された場合、FindFunction は null を返すため、必ず戻り値を条件分岐で確認してください(FindFunctionChecked は代わりにアサートします)。C++ が契約を所有する場合は、コンパイル時に型チェックされる BlueprintImplementableEvent の宣言を優先してください。
// SpawnClassPath is a UPROPERTY(EditDefaultsOnly) TSoftClassPtr<AMyActor> set to BP_MyThing
void MyInspectSpawnClass(const TSoftClassPtr<AMyActor>& SpawnClassPath)
{
if (UClass* LoadedClass = SpawnClassPath.LoadSynchronous())
{
const AMyActor* Defaults = LoadedClass->GetDefaultObject<AMyActor>();
const bool bIsBlueprintClass = Cast<UBlueprintGeneratedClass>(LoadedClass) != nullptr; // UClass hides IsA (Class.h:4853)
UE_LOG(LogMyGame, Log, TEXT("Default health %.1f, Blueprint class %d"), Defaults->GetHealth(), bIsBlueprintClass ? 1 : 0);
}
}
LoadSynchronous はゲームスレッドをブロックします。ストリーミング読み込みには Asset Manager を使用してください(ue-data-assets-tables)。UBlueprintGeneratedClass(Engine/BlueprintGeneratedClass.h)は、コンパイル済み Blueprint が生成する実行時の UClass です。ネイティブクラスと Blueprint クラスを異なる方法で処理する必要がある場合は、これを使って判定してください。
Blueprint のサブシステムと設定
- すべての
UGameInstanceSubsystem、UWorldSubsystem、ULocalPlayerSubsystem、UEngineSubsystemのサブクラスには、Get <Subsystem>ノード(UK2Node_GetSubsystem)が自動的に追加されます。そのオブジェクトでは、BlueprintCallableメンバーを呼び出せます。追加の指定子は必要ありません。サブシステムのライフタイムとネイティブアクセサーについては、ue-cpp-foundationsを参照してください。 UDeveloperSettings(Engine/DeveloperSettings.h、モジュールDeveloperSettings)を使用すると、Project Settings のページが自動的に登録されます。UCLASS(Config=Game, DefaultConfig, meta=(DisplayName="My Game"))として宣言し、フィールドにUPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category=…)を指定してください。また、GetDefault<UMyGameSettings>()を返すUFUNCTION(BlueprintPure)の静的アクセサーを追加してください。Blueprint にはGetDefaultのノードがありません。ページの場所を変更するには、GetContainerName()、GetCategoryName()、GetSectionName()をオーバーライドできます。UFUNCTION(Exec)はコンソールコマンドを宣言します。コンソールは PlayerInput、PlayerController、Pawn、HUD、GameMode、CheatManager、GameState、PlayerCameraManager、GameInstance にコマンドをルーティングします。meta=(DevelopmentOnly)を指定すると、UKismetSystemLibrary::PrintStringと同様に、Shipping ビルドではBlueprintCallableがコンパイル対象から除外されます。
エディターから呼び出せる関数
CallInEditor(上記の AMyActor::SnapToGround を参照)は UFUNCTION 指定子であり、meta= キーではありません。また、関数はパラメーターを受け取りません。エディターワールドで実行されるため、PIE を前提とする処理にはガードを設けてください。Details のカスタマイズ、エディターユーティリティウィジェット、アセットアクションについては、ue-editor-tools を参照してください。
非推奨 — 使用しないでください
| 出力しないもの | 5.8 で使用するもの | 出典 |
|---|---|---|
meta=(HideAssetPicker) | meta=(HidePinAssetPicker) | UObject/ObjectMacros.h:1673 の UE_DEPRECATED(5.6) |
Delegate.ProcessMulticastDelegate<UObject>(Params) | Delegate.ProcessDelegate<UObject>(Params) | UObject/ScriptDelegates.h:1462 の UE_DEPRECATED(5.8) |
SomeClass->ClassDefaultObject | GetDefault<T>()、UClass::GetDefaultObject<T>() | UObject/Class.h:4045 の UE_DEPRECATED(5.6) |
GENERATED_UCLASS_BODY()、GENERATED_IINTERFACE_BODY() | GENERATED_BODY() | UObject/ObjectMacros.h:802-805 のレガシーエイリアス |
Blueprint 実装クラスに対する Cast<IMyInterface>(Obj)->Foo() | IMyInterface::Execute_Foo(Obj, …) | Blueprint 実装クラスには IMyInterface ポインターがありません(UObject/ScriptInterface.h:135) |
BlueprintNativeEvent を呼び出すための Obj->Foo_Implementation() | Obj->Foo() | 通常の名前は生成されたディスパッチサンクです(UObject/ObjectMacros.h:997) |
BlueprintImplementableEvent の C++ 本体 | 宣言のみ行い、そこで終える | UHT が本体を生成します(UObject/ObjectMacros.h:992) |
private メンバーへの UPROPERTY(BlueprintReadWrite) | meta=(AllowPrivateAccess="true") を追加するか、protected にする | UHT エラー「BlueprintReadWrite should not be used on private members」 |
UENUM(BlueprintType) enum class EMyState : uint32 | enum class EMyState : uint8 | UHT エラー「Invalid BlueprintType enum base - currently only uint8 supported」 |
UPROPERTY 内の TArray<TArray<T>> または TMap<K, TArray<V>> | 内側のコンテナーを USTRUCT でラップする | UHT では TArray/TMap が CanBeContainerValue/CanBeContainerKey をクリアします |
FindExistingAction によるガードなしの AddNewAction | まず LatentInfo.UUID を確認する | Engine/LatentActionManager.h:121,143 |
登録せずに返す NewObject<UMyAsyncAction>() | RegisterWithGameInstance(WorldContextObject) | Kismet/BlueprintAsyncActionBase.h:37 |
よくある間違い
BlueprintNativeEvent に _Implementation がない、または BlueprintImplementableEvent に C++ の本体がある: 前者は未解決の外部シンボルになり、後者は重複シンボルになります(UHT がすでに生成しています)。ネイティブイベントでは virtual void Foo_Implementation(...) を定義する必要があります。実装可能イベントでは定義は一切不要です。
副作用のある BlueprintPure: コンパイラーは使われていない純粋ノードを削除し、残りを各コンシューマーで再評価するため、副作用が予測できない回数だけ実行されます。BlueprintCallable を使用してください。
入力として使うつもりだった非 const 参照パラメーター:
static void Scale(FVector& Value, double Factor); // WRONG: Value becomes an output pin
static void Scale(UPARAM(ref) FVector& Value, double Factor); // RIGHT: by-reference input
static void Scale(const FVector& Value, double Factor); // RIGHT: plain input
ワールドが必要なライブラリ関数で WorldContext を宣言していない: UBlueprintFunctionLibrary の CDO では GetWorld() は null を返します。const UObject* WorldContextObject を受け取り、meta=(WorldContext="WorldContextObject") を指定して、GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull) で解決してください。
private メンバーに BlueprintReadWrite を指定する: 警告ではなく UHT エラーになります。meta=(AllowPrivateAccess="true") を追加してください。
UPROPERTY 内のネストしたコンテナー: UHT は TArray<TArray<T>> と TMap<K, TArray<V>> を拒否します。内側のコンテナーを USTRUCT(BlueprintType) でラップしてください。
UUID ガードなしで潜在アクションを追加する: ノードが再入するとアクションが重複して積み重なり、完了ピンがコピーごとに 1 回ずつ実行されます。まず FindExistingAction<FMyWaitAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) を確認してください。
実行中に非同期アクションがガベージコレクションされる: RegisterWithGameInstance を呼び出さないアクションは、作成されたフレームの間しか存続しないため、後でデリゲートが発火してもアクションに届きません。ファクトリー内で登録し、完了時に SetReadyToDestroy() を 1 回だけ呼び出してください。
Blueprint の実装クラスに対して Cast<IMyInterface>(Obj) を使う: null が返り、呼び出しは黙ってスキップされます。Obj->Implements<UMyInterface>() で確認し、IMyInterface::Execute_Foo(Obj, …) で呼び出してください。
meta=(BlueprintInternalUseOnly="true") のない静的非同期ファクトリー: Blueprint にプロキシノードとファクトリーの直接呼び出しの両方が表示され、直接呼び出しでは何もアクティブ化されないオブジェクトが返されます。
関連スキル
ue-cpp-foundations—UCLASS/UPROPERTY/UFUNCTIONの基礎、コンテナー、デリゲート、サブシステムのライフタイム、GCue-actor-component-architecture— Actor とコンポーネントのライフサイクル、スポーン、BlueprintSpawnableComponentue-gameplay-framework— GameMode、PlayerController、ダメージ、Blueprint で拡張されることが最も多いクラスue-editor-tools— 詳細パネルのカスタマイズ、エディターユーティリティウィジェット、アセットアクション、エディターサブシステムue-async-threading— 非同期ノードの内部で使用するAsyncTask、UE::Tasks、タイマー、スレッドセーフue-data-assets-tables—UDataAsset、DataTable の行、ソフト参照、Asset Manager による読み込みue-ui-umg-slate—UUserWidgetの C++ 基底クラス、BindWidget、Blueprint へのウィジェットデータの公開