mcpField
U
ue-blueprint-cpp-interop

ue-blueprint-cpp-interop

github.com/quodsoler開発419255 回インストール4 週間前に更新
リポジトリ

ue-blueprint-cpp-interop について

UE 5.8 の C++ と Blueprint の連携を扱う開発スキルです。リフレクション指定子によるノード構成や、ネイティブコードから Blueprint にデータ、処理、イベントを公開する方法を説明します。

主な機能

  1. 01UFUNCTION のノードとイベント設定
  2. 02UPROPERTY のデータ公開規則
  3. 03関数ライブラリと非同期ノードの実装パターン
  4. 04Blueprint インターフェースとデリゲートの処理
  5. 05ネイティブコードからの Blueprint 呼び出し

活用シーン

  1. 01C++ 関数を Blueprint から呼び出し・オーバーライド
  2. 02プロパティの Blueprint 読み書き設定
  3. 03遅延または非同期 Blueprint ノードの実装
  4. 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、DefaultToSelfFunction Libraries
後から完了する実行ピンを持つノード(Delay 形式)Latent Nodes
イベント発生時に実行される複数の出力実行ピンを持つノードAsync Action Nodes
Blueprint で実装できるインターフェース、Execute_、TScriptInterfaceBlueprint 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 を暗黙に含みます自分で実装、副作用なし
BlueprintImplementableEventBlueprint が実装するイベントなし — UHT がサンクを生成します
BlueprintNativeEventBlueprint がオーバーライドできるイベント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 での効果
BlueprintReadWriteGet ノードと Set ノード
BlueprintReadOnlyGet ノードのみ
BlueprintGetter=FnGet は UFUNCTION(BlueprintGetter) を経由します
BlueprintSetter=FnSet は UFUNCTION(BlueprintSetter) を経由します。BlueprintReadWrite も暗黙的に指定されます
BlueprintAssignableBind Event ノード(マルチキャスト動的デリゲートのみ)
BlueprintCallableBroadcast ノード(マルチキャスト動的デリゲートのみ)
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/floatReal
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->ClassDefaultObjectGetDefault<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 : uint32enum class EMyState : uint8UHT エラー「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 の基礎、コンテナー、デリゲート、サブシステムのライフタイム、GC
  • ue-actor-component-architecture — Actor とコンポーネントのライフサイクル、スポーン、BlueprintSpawnableComponent
  • ue-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 へのウィジェットデータの公開

コメント