ue-blueprint-cpp-interop
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUE Blueprint / C++ Interop
UE Blueprint / C++ 互操作
Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
This skill covers the boundary between native code and the Blueprint VM: which / specifiers and keys produce which node shapes, function libraries, latent and async nodes, Blueprint-implementable interfaces, and how C++ calls back into a Blueprint graph. Everything here lives in , and (); Project Settings pages also need . The authority for every specifier is — anything not declared in its , , , , or enumerations is not a specifier.
UFUNCTIONUPROPERTYmeta=CoreCoreUObjectEnginePublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });DeveloperSettingsRuntime/CoreUObject/Public/UObject/ObjectMacros.hUCUIUFUPUSUM目标引擎版本:UE 5.8。以下API均已对照5.8版本头文件验证;旧版用法列在「已弃用 — 请勿使用」章节中。
本技能覆盖原生代码与Blueprint VM之间的交互边界:哪些/说明符和键会生成对应类型的节点、函数库、latent与异步节点、Blueprint可实现接口,以及C++如何回调Blueprint图表。本文涉及的所有内容均位于、和模块中();项目设置页面还需要模块。所有说明符的权威定义位于——任何未在其、、、、或枚举中声明的内容都不是合法说明符。
UFUNCTIONUPROPERTYmeta=CoreCoreUObjectEnginePublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });DeveloperSettingsRuntime/CoreUObject/Public/UObject/ObjectMacros.hUCUIUFUPUSUMContext
上下文
Read if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.
.agents/ue-project-context.mdIdentify the area from the request and the codebase. Ask only when two plausible readings would produce different code.
| Request is about… | Go to |
|---|---|
| Making a C++ function callable or overridable in Blueprint | UFUNCTION Exposure |
| Making data visible or editable in Blueprint, getters/setters | UPROPERTY Exposure |
Static helpers, | Function Libraries |
| A node with an exec pin that finishes later (Delay-style) | Latent Nodes |
| A node with several output exec pins that fire on events | Async Action Nodes |
Interfaces Blueprint can implement, | Blueprint Interfaces |
| Enums and Structs in Blueprint |
| Delegates and Events |
| Running Blueprint logic from native code, Blueprint classes | Calling Blueprint from Native Code |
Subsystems, | Subsystems and Settings in Blueprint |
| A button in the Details panel, editor-only actions | Editor-Callable Functions |
如果存在文件请先阅读(包含模块名、编码规范、启用的插件、GAS/网络配置等信息)。若文件不存在也无需中断。
.agents/ue-project-context.md根据用户请求和代码库确定具体涉及的领域。仅当两种合理的解读会生成完全不同的代码时,才向用户提问确认。
| 用户请求涉及… | 前往 |
|---|---|
| 让C++函数可在Blueprint中调用或重写 | UFUNCTION 暴露 |
| 让数据在Blueprint中可见或可编辑、getter/setter | UPROPERTY 暴露 |
静态辅助函数、 | 函数库 |
| 带有exec引脚且延迟完成的节点(Delay风格) | Latent节点 |
| 带有多个输出exec引脚、在事件触发时执行的节点 | 异步动作节点 |
Blueprint可实现的接口、 | Blueprint接口 |
| Blueprint中的枚举与结构体 |
| 委托与事件 |
| 从原生代码运行Blueprint逻辑、Blueprint类 | 从原生代码调用Blueprint |
子系统、 | Blueprint中的子系统与设置 |
| 详情面板中的按钮、仅编辑器可用的操作 | 编辑器可调用函数 |
UFUNCTION Exposure
UFUNCTION 暴露 {#ufunction-exposure}
| Specifier | Node shape | C++ body |
|---|---|---|
| Exec pins in and out | Yours |
| No exec pins; implies | Yours, side-effect free |
| Event the Blueprint implements | None — UHT generates the thunk |
| Event the Blueprint may override | |
| Hidden; reached through the property | Yours |
| Blueprint calls are skipped without network authority (direct C++ calls still run) | Yours |
| Blueprint calls are skipped on a dedicated server (direct C++ calls still run) | Yours |
| Not offered in the palette; only generated nodes call it | Yours |
| Button on the Details panel | Yours |
| Console command | Yours |
Category="A\|B"meta=DisplayNameToolTipKeywordsCompactNodeTitleAdvancedDisplayReturnDisplayNameHidePinDeterminesOutputTypeDynamicOutputParamArrayParmExpandEnumAsExecsWorldContextUnsafeDuringActorConstructionDevelopmentOnlyBlueprintThreadSafecpp
// 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;
};cpp
// 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 BlueprintRaise an event by its plain name (), never — the plain name is the generated thunk that dispatches to Blueprint. A subclass overrides and chains with , never .
OnDied()OnDied_Implementation()virtual void OnDied_Implementation() override;Super::OnDied_Implementation();Super::OnDied();| 说明符 | 节点形态 | C++实现 |
|---|---|---|
| 带输入输出exec引脚 | 用户自行实现 |
| 无exec引脚;隐含 | 用户自行实现,无副作用 |
| Blueprint实现的事件 | 无需实现 —— 由UHT生成转接函数 |
| Blueprint可重写的事件 | 仅需实现 |
| 隐藏;通过属性访问 | 用户自行实现 |
| 无网络权限时跳过Blueprint调用(直接C++调用仍会执行) | 用户自行实现 |
| 在专用服务器上跳过Blueprint调用(直接C++调用仍会执行) | 用户自行实现 |
| 不在节点面板中显示;仅生成的节点可调用 | 用户自行实现 |
| 详情面板中的按钮 | 用户自行实现 |
| 控制台命令 | 用户自行实现 |
Category="A\|B"meta=DisplayNameToolTipKeywordsCompactNodeTitleAdvancedDisplayReturnDisplayNameHidePinDeterminesOutputTypeDynamicOutputParamArrayParmExpandEnumAsExecsWorldContextUnsafeDuringActorConstructionDevelopmentOnlyBlueprintThreadSafecpp
// 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;
};cpp
// 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触发事件时请使用其原始名称(),绝对不要调用——原始名称对应的是UHT生成的、负责调度到Blueprint的转接函数。子类重写时应使用,并通过调用父类实现,绝不要调用。
OnDied()OnDied_Implementation()virtual void OnDied_Implementation() override;Super::OnDied_Implementation();Super::OnDied();Parameters and pins
参数与引脚 {#parameters-and-pins}
| C++ parameter | Blueprint pin |
|---|---|
| Input |
| Input, passed by reference |
| Output pin, not an input |
| By-reference input that is also an output |
| Input renamed on the node |
A bare gets the flag from UHT; adds so the pin stays an input. gives a reference input an inline literal when nothing is connected.
T&OutParmUPARAM(ref)ReferenceParmmeta=(AutoCreateRefTerm="Offset")| C++参数 | Blueprint引脚 |
|---|---|
| 输入引脚 |
| 输入引脚,按引用传递 |
| 输出引脚,而非输入 |
| 按引用传递的输入引脚,同时也是输出 |
| 输入引脚在节点上重命名 |
裸的参数会被UHT标记为(输出参数);会添加标记,使引脚保持为输入类型。可以让引用输入引脚在未连接任何内容时显示内联字面量输入框。
T&OutParmUPARAM(ref)ReferenceParmmeta=(AutoCreateRefTerm="Offset")UPROPERTY Exposure
UPROPERTY 暴露 {#uproperty-exposure}
| Specifier | Effect in Blueprint |
|---|---|
| Get and Set nodes |
| Get node only |
| Get routes through |
| Set routes through |
| Bind Event node (multicast dynamic delegates only) |
| Broadcast node (multicast dynamic delegates only) |
| Delegate accepts only |
BlueprintReadWriteBlueprintReadOnlyprivatemeta=(AllowPrivateAccess="true")meta=ClampMinClampMaxUIMinUIMaxEditConditionEditConditionHidesInlineEditConditionToggleTitlePropertyShowOnlyInnerPropertiesMultiLineGetOptionsAllowedClassesMustImplementCategoriesBitmaskBitmaskEnumExposeOnSpawn| C++ member type | Blueprint pin |
|---|---|
| Real |
| Object reference |
| Class (filtered by |
| Soft reference; Blueprint resolves or loads on demand |
| Struct pin whose concrete type is chosen in the editor |
| Interface reference |
| Bind Event / Broadcast nodes via |
| |
A worked component showing , /, , and a / pair: references/blueprint-meta-specifiers.md.
ExposeOnSpawnEditConditionEditConditionHidesInlineEditConditionToggleMustImplementBlueprintGetterBlueprintSetterFloats and doubles. Both and properties show as a Blueprint Real pin ( maps and to with sub-category /), and Blueprint-authored variables are doubles. Declare for scalars that flow through Blueprint math so no narrowing conversion is inserted; keep only where the engine type is already float.
floatdoubleUEdGraphSchema_K2FFloatPropertyFDoublePropertyPC_RealPC_FloatPC_Doubledoublefloat| 说明符 | 在Blueprint中的效果 |
|---|---|
| 生成Get和Set节点 |
| 仅生成Get节点 |
| Get操作通过 |
| Set操作通过 |
| 生成Bind Event节点(仅适用于多播动态委托) |
| 生成Broadcast节点(仅适用于多播动态委托) |
| 委托仅接受标记为 |
在成员上使用/会触发UHT错误(提示「BlueprintReadWrite should not be used on private members」),除非该属性添加了标记。仅编辑器可用的属性不能作为Blueprint可暴露的结构体成员。编辑器相关的键(/、/、、、、、、、、、、、/、)请参见:references/blueprint-meta-specifiers.md。
privateBlueprintReadWriteBlueprintReadOnlymeta=(AllowPrivateAccess="true")meta=ClampMinClampMaxUIMinUIMaxEditConditionEditConditionHidesInlineEditConditionToggleTitlePropertyShowOnlyInnerPropertiesMultiLineGetOptionsAllowedClassesMustImplementCategoriesBitmaskBitmaskEnumExposeOnSpawn| C++成员类型 | Blueprint引脚 |
|---|---|
| Real(实数) |
| 对象引用 |
| 类(可通过 |
| 软引用;Blueprint按需解析或加载 |
| 结构体引脚,具体类型可在编辑器中选择 |
| 接口引用 |
| 通过 |
| 标记为 |
展示、/、、以及/配对用法的完整组件示例请参见:references/blueprint-meta-specifiers.md。
ExposeOnSpawnEditConditionEditConditionHidesInlineEditConditionToggleMustImplementBlueprintGetterBlueprintSetterfloat与double。 和属性在Blueprint中都会显示为Real(实数)引脚(会将和映射为类型,子类别分别为/),且Blueprint中创建的变量默认是double类型。对于会在Blueprint中参与数学运算的标量,请声明为以避免窄化转换;仅在引擎本身使用float的场景下保留类型。
floatdoubleUEdGraphSchema_K2FFloatPropertyFDoublePropertyPC_RealPC_FloatPC_DoubledoublefloatFunction Libraries
函数库 {#function-libraries}
UBlueprintFunctionLibraryKismet/BlueprintFunctionLibrary.hUCLASS(Abstract)staticGetWorld()const UObject* WorldContextObjectmeta=(WorldContext="WorldContextObject")GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)meta=(DefaultToSelf="Param")cpp
// 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);
};The matching : references/blueprint-node-patterns.md. accepts exactly one input parameter (UHT errors on a second); name to expand the return value, and use for a bool. Wildcard array nodes use .
.cppExpandEnumAsExecsReturnValueExpandBoolAsExecsmeta=(ArrayParm="Items", ArrayTypeDependentParams="Item")UBlueprintFunctionLibraryKismet/BlueprintFunctionLibrary.hUCLASS(Abstract)staticGetWorld()const UObject* WorldContextObjectmeta=(WorldContext="WorldContextObject")GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)meta=(DefaultToSelf="Param")cpp
// 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);
};对应的实现请参见:references/blueprint-node-patterns.md。仅接受一个输入参数(第二个会触发UHT错误);若要展开返回值,将参数命名为即可;对于bool类型请使用。通配符数组节点使用。
.cppExpandEnumAsExecsReturnValueExpandBoolAsExecsmeta=(ArrayParm="Items", ArrayTypeDependentParams="Item")Latent Nodes
Latent节点 {#latent-nodes}
A latent node holds one exec pin pending across frames. It needs and a trailing parameter, plus an subclass registered with the world's . and () are the engine reference.
meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject")FLatentActionInfoFPendingLatentActionFLatentActionManagerUKismetSystemLibrary::DelayFDelayActionEngine/Public/DelayAction.hcpp
// 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);cpp
// 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));
}
}
}Without the guard, re-entering the node stacks a second action on the same UUID and the exec pin fires more than once. The action subclass overrides and finishes with , copying , and out of the in its constructor; it also overrides , and, under , . additionally offers and for several exit links. Complete subclass and the rest of the API: references/blueprint-node-patterns.md.
FindExistingActionUpdateOperation(FLatentResponse& Response)Response.FinishAndTriggerIf(bDone, ExecutionFunction, OutputLink, CallbackTarget)ExecutionFunctionLinkageCallbackTargetFLatentActionInfoNotifyObjectDestroyed()NotifyActionAborted()WITH_EDITORGetDescription() constFLatentResponseDoneIf(bool)TriggerLink(ExecutionFunction, LinkID, CallbackTarget)FLatentActionManagerLatent节点会将一个exec引脚挂起,跨帧等待执行完成。它需要添加标记,以及一个末尾的参数,此外还需要一个的子类,并将其注册到World的中。和(位于)是引擎自带的参考实现。
meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject")FLatentActionInfoFPendingLatentActionFLatentActionManagerUKismetSystemLibrary::DelayFDelayActionEngine/Public/DelayAction.hcpp
// MyLatentLibrary.h — 声明
UFUNCTION(BlueprintCallable, Category="MyGame|Flow", meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject", Duration="1.0"))
static void WaitSeconds(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo);cpp
// MyLatentLibrary.cpp — UUID保护是必须的
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));
}
}
}如果没有的保护,重复进入该节点会在同一个UUID上堆叠第二个动作,导致exec引脚触发多次。动作子类需要重写,并通过标记完成,其中、和需要在构造函数中从里复制出来;同时还需要重写、,以及在宏下重写。还提供了和用于支持多个输出引脚。完整的子类实现以及的其他API请参见:references/blueprint-node-patterns.md。
FindExistingActionUpdateOperation(FLatentResponse& Response)Response.FinishAndTriggerIf(bDone, ExecutionFunction, OutputLink, CallbackTarget)ExecutionFunctionLinkageCallbackTargetFLatentActionInfoNotifyObjectDestroyed()NotifyActionAborted()WITH_EDITORGetDescription() constFLatentResponseDoneIf(bool)TriggerLink(ExecutionFunction, LinkID, CallbackTarget)FLatentActionManagerAsync Action Nodes
异步动作节点 {#async-action-nodes}
UBlueprintAsyncActionBaseKismet/BlueprintAsyncActionBase.hBlueprintAssignablemeta=(BlueprintInternalUseOnly="true")cpp
// 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;
};The factory does , stores its inputs, calls and returns the action; the node then binds the delegates and calls , where the work starts. Each completion path broadcasts once and calls . An unregistered action lives only for the frame it was created on (), so a delegate firing later finds it collected. The engine ensures when more than (default 10000) actions are alive at once.
NewObject<UMyWaitForHealthAction>()RegisterWithGameInstance(WorldContextObject)Activate()SetReadyToDestroy()RF_StrongRefOnFramebp.MaxAsyncActionCountUCancellableAsyncActionEngine/CancellableAsyncAction.hUCLASS(Abstract, BlueprintType, meta=(ExposedAsyncProxy=AsyncAction))Cancel()IsActive() constShouldBroadcastDelegates() constShouldBroadcastDelegates()ActivateCancelUBlueprintAsyncActionBaseKismet/BlueprintAsyncActionBase.hBlueprintAssignablemeta=(BlueprintInternalUseOnly="true")cpp
// 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; // 一个输出exec引脚
UPROPERTY(BlueprintAssignable)
FMyHealthThresholdSignature OnFailed; // 第二个输出exec引脚
private:
UFUNCTION()
void HandleHealthChanged(double NewHealth); // AddDynamic的目标必须是UFUNCTION
UPROPERTY()
TObjectPtr<UMyStatsComponent> TrackedStats;
double ThresholdValue = 0.0;
};工厂函数会执行,存储输入参数,调用,然后返回动作对象;之后节点会绑定委托并调用,正式开始执行逻辑。每个完成路径都应广播一次委托并调用。未注册的动作对象仅在创建它的那一帧有效(标记为),因此之后触发的委托会找不到已被回收的对象。当同时存活的动作数量超过(默认10000)时,引擎会进行相应处理。
NewObject<UMyWaitForHealthAction>()RegisterWithGameInstance(WorldContextObject)Activate()SetReadyToDestroy()RF_StrongRefOnFramebp.MaxAsyncActionCountUCancellableAsyncActionEngine/CancellableAsyncAction.hUCLASS(Abstract, BlueprintType, meta=(ExposedAsyncProxy=AsyncAction))Cancel()IsActive() constShouldBroadcastDelegates() constShouldBroadcastDelegates()ActivateCancelBlueprint Interfaces
Blueprint接口 {#blueprint-interfaces}
UINTERFACEUI::MinimalAPIBlueprintableNotBlueprintableConversionRootmeta=BlueprintTypeBlueprintImplementableEventBlueprintNativeEventvirtualcpp
// 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
};cpp
// 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);
}| Form | C++ implementers | Blueprint implementers |
|---|---|---|
| Yes | Yes — always use this |
| Yes | Yes |
| Yes | Yes |
| Yes | No — the cast returns null |
| Yes | Interface pointer is null; still call through |
TScriptInterface<T>UObject/ScriptInterface.hUPROPERTY(EditAnywhere, BlueprintReadWrite) TScriptInterface<IMyInteractable> Target;Execute_UINTERFACEUI::MinimalAPIBlueprintableNotBlueprintableConversionRootmeta=BlueprintTypeBlueprintImplementableEventBlueprintNativeEventvirtualcpp
// 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; } // 仅原生:对Blueprint不可见
};cpp
// 调用可能由C++或Blueprint实现的接口
bool MyTryInteract(UObject* Target, AActor* Interactor)
{
return Target && Target->Implements<UMyInteractable>()
&& IMyInteractable::Execute_Interact(Target, Interactor);
}| 调用方式 | C++实现者 | Blueprint实现者 |
|---|---|---|
| 支持 | 支持 —— 请始终使用这种方式 |
| 支持 | 支持 |
| 支持 | 支持 |
| 支持 | 不支持 —— 转换会返回null |
| 支持 | 接口指针为null;仍需通过 |
TScriptInterface<T>UObject/ScriptInterface.hUPROPERTY(EditAnywhere, BlueprintReadWrite) TScriptInterface<IMyInteractable> Target;Execute_Enums and Structs in Blueprint
Blueprint中的枚举与结构体 {#enums-and-structs-in-blueprint}
cpp
// 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;
};- requires
UENUM(BlueprintType); UHT rejects any other base ("Invalid BlueprintType enum base - currently only uint8 supported").enum class : uint8renames an enumerator andUMETA(DisplayName="…")hides it from pickers.UMETA(Hidden) - gives Make and Break nodes. Structs cannot hold
USTRUCT(BlueprintType)s — put struct helpers in a function library.UFUNCTION - No nested containers. ,
TArrayandTSetclear their own "can be a container key/value" capability in UHT, soTMapandTArray<TArray<int32>>do not compile. Wrap the inner container in aTMap<FName, TArray<int32>>.USTRUCT - A container is Blueprint-exposable only when its element type — and for its key type — is itself Blueprint-supported.
TMap - (
FTableRowBase) isEngine/DataTable.h; derive row structs from it and mark the derived structUSTRUCT(BlueprintInternalUseOnly). Table loading and row lookup:BlueprintType.ue-data-assets-tables - (
FInstancedStruct) isStructUtils/InstancedStruct.hand gives Blueprint a single pin whose concrete struct type is chosen in the editor;USTRUCT(BlueprintType)is the typed C++ wrapper.TInstancedStruct<FMyBase>
cpp
// MyTypes.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "MyTypes.generated.h"
UENUM(BlueprintType)
enum class EMyWeaponState : uint8 // BlueprintType枚举必须基于uint8
{
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; // Blueprint支持类型的容器
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
TMap<FName, double> Modifiers; // 键和值都必须是Blueprint支持的类型
};
USTRUCT(BlueprintType)
struct MYGAME_API FMyWeaponRow : public FTableRowBase // 数据表行类型
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
FMyWeaponStats Stats;
};- 要求枚举必须是
UENUM(BlueprintType)类型;UHT会拒绝其他任何底层类型(提示「Invalid BlueprintType enum base - currently only uint8 supported」)。enum class : uint8可以重命名枚举项,UMETA(DisplayName="…")可以在选择器中隐藏该枚举项。UMETA(Hidden) - 会生成Make和Break节点。结构体中不能包含
USTRUCT(BlueprintType)——请将结构体的辅助函数放在函数库中。UFUNCTION - 不支持嵌套容器。 、
TArray和TSet在UHT中会清除自身的「可作为容器键/值」能力,因此TMap和TArray<TArray<int32>>无法编译。请将内层容器包装在一个TMap<FName, TArray<int32>>中。USTRUCT - 只有当容器的元素类型(对于来说还包括键类型)本身是Blueprint支持的类型时,该容器才能暴露给Blueprint。
TMap - (位于
FTableRowBase)声明为Engine/DataTable.h;请从它派生数据表行结构体,并将派生结构体标记为USTRUCT(BlueprintInternalUseOnly)。数据表加载与行查找请参见BlueprintType。ue-data-assets-tables - (位于
FInstancedStruct)声明为StructUtils/InstancedStruct.h,在Blueprint中显示为单个引脚,具体结构体类型可在编辑器中选择;USTRUCT(BlueprintType)是其类型安全的C++包装器。TInstancedStruct<FMyBase>
Delegates and Events
委托与事件 {#delegates-and-events}
Only dynamic delegates cross the Blueprint boundary. Declaration macros and native binding rules: .
ue-cpp-foundations- on a multicast dynamic delegate gives Blueprint a Bind Event node; adding
UPROPERTY(BlueprintAssignable)also gives it a Broadcast node. Both are legal only on multicast dynamic delegates.BlueprintCallable - Delegate parameters need names — they become the pin names on the event node.
- Any C++ handler bound with must be a
AddDynamic; otherwise the name lookup fails at runtime and the handler never runs.UFUNCTION() - A single dynamic delegate (,
DECLARE_DYNAMIC_DELEGATE, …) works as aDECLARE_DYNAMIC_DELEGATE_OneParamparameter, which is how async nodes take a one-shot callback:UFUNCTION.UPARAM(DisplayName="Event") FMyReadySignature Callback - Native (non-dynamic) delegates cannot be exposed at all; wrap them in a dynamic delegate or an async action.
只有动态委托可以跨越Blueprint边界。委托声明宏和原生绑定规则请参见。
ue-cpp-foundations- 在多播动态委托上添加会在Blueprint中生成Bind Event节点;再加上
UPROPERTY(BlueprintAssignable)还会生成Broadcast节点。这两个说明符仅对多播动态委托有效。BlueprintCallable - 委托参数必须有名称——它们会成为事件节点上的引脚名称。
- 任何通过绑定的C++处理函数都必须是
AddDynamic;否则运行时名称查找会失败,处理函数永远不会执行。UFUNCTION() - 单播动态委托(、
DECLARE_DYNAMIC_DELEGATE等)可以作为DECLARE_DYNAMIC_DELEGATE_OneParam的参数,这也是异步节点接收一次性回调的方式:UFUNCTION。UPARAM(DisplayName="Event") FMyReadySignature Callback - 原生(非动态)委托完全无法暴露给Blueprint;请将它们包装在动态委托或异步动作中。
Calling Blueprint from Native Code
从原生代码调用Blueprint {#calling-blueprint-from-native-code}
| Need | Use |
|---|---|
| A hook the designer fills in | |
| A hook with a C++ default | |
| Fire an event many graphs listen to | |
| Call a function that exists only in a Blueprint asset | |
| Read defaults off a Blueprint class | |
cpp
// 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);
}
}FindFunctionFindFunctionCheckedBlueprintImplementableEventcpp
// 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);
}
}LoadSynchronousue-data-assets-tablesUBlueprintGeneratedClassEngine/BlueprintGeneratedClass.hUClass| 需求 | 使用方式 |
|---|---|
| 设计师需要填充的钩子 | |
| 带有C++默认实现的钩子 | |
| 触发多个图表监听的事件 | |
| 调用仅存在于Blueprint资产中的函数 | |
| 读取Blueprint类的默认值 | |
cpp
// 参数结构体必须与函数的参数列表完全匹配,按声明顺序排列。
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被重命名或重新编译后,会返回null,因此必须先判断返回值再使用(会直接断言)。只要契约由C++定义,就应优先使用声明——它会在编译期进行类型检查。
FindFunctionFindFunctionCheckedBlueprintImplementableEventcpp
// SpawnClassPath是一个UPROPERTY(EditDefaultsOnly) TSoftClassPtr<AMyActor>,设置为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隐藏了IsA (Class.h:4853)
UE_LOG(LogMyGame, Log, TEXT("Default health %.1f, Blueprint class %d"), Defaults->GetHealth(), bIsBlueprintClass ? 1 : 0);
}
}LoadSynchronousue-data-assets-tablesUBlueprintGeneratedClassEngine/BlueprintGeneratedClass.hUClassSubsystems and Settings in Blueprint
Blueprint中的子系统与设置 {#subsystems-and-settings-in-blueprint}
- Every ,
UGameInstanceSubsystem,UWorldSubsystemandULocalPlayerSubsystemsubclass automatically gets aUEngineSubsystemnode (Get <Subsystem>); itsUK2Node_GetSubsystemmembers then appear on that object. No extra specifier is needed. Subsystem lifetimes and native accessors:BlueprintCallable.ue-cpp-foundations - (
UDeveloperSettings, moduleEngine/DeveloperSettings.h) auto-registers a Project Settings page. Declare itDeveloperSettings, mark fieldsUCLASS(Config=Game, DefaultConfig, meta=(DisplayName="My Game")), and add aUPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category=…)static accessor returningUFUNCTION(BlueprintPure)— Blueprint has no node forGetDefault<UMyGameSettings>().GetDefault,GetContainerName()andGetCategoryName()are overridable to move the page.GetSectionName() - declares a console command; the console routes to PlayerInput, PlayerController, Pawn, HUD, GameMode, CheatManager, GameState, PlayerCameraManager and GameInstance.
UFUNCTION(Exec)compiles ameta=(DevelopmentOnly)out of Shipping, asBlueprintCallabledoes.UKismetSystemLibrary::PrintString
- 所有、
UGameInstanceSubsystem、UWorldSubsystem和ULocalPlayerSubsystem的子类都会自动获得一个UEngineSubsystem节点(Get <Subsystem>);其标记为UK2Node_GetSubsystem的成员会显示在该对象上。无需额外的说明符。子系统生命周期和原生访问方式请参见BlueprintCallable。ue-cpp-foundations - (位于
UDeveloperSettings,属于Engine/DeveloperSettings.h模块)会自动注册一个项目设置页面。将其声明为DeveloperSettings,将字段标记为UCLASS(Config=Game, DefaultConfig, meta=(DisplayName="My Game")),并添加一个UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category=…)静态访问函数返回UFUNCTION(BlueprintPure)——Blueprint没有直接调用GetDefault<UMyGameSettings>()的节点。可以重写GetDefault、GetContainerName()和GetCategoryName()来调整设置页面的位置。GetSectionName() - 用于声明控制台命令;控制台会将命令路由到PlayerInput、PlayerController、Pawn、HUD、GameMode、CheatManager、GameState、PlayerCameraManager和GameInstance。
UFUNCTION(Exec)会让meta=(DevelopmentOnly)函数在Shipping版本中被编译掉,和BlueprintCallable的行为一致。UKismetSystemLibrary::PrintString
Editor-Callable Functions
编辑器可调用函数 {#editor-callable-functions}
CallInEditorAMyActor::SnapToGroundUFUNCTIONmeta=ue-editor-toolsCallInEditorAMyActor::SnapToGroundUFUNCTIONmeta=ue-editor-toolsDeprecated — do not use
已弃用 — 请勿使用 {#deprecated-do-not-use}
| Do not emit | Use in 5.8 | Source |
|---|---|---|
| | |
| | |
| | |
| | Legacy aliases in |
| | Blueprint implementers have no |
| | The plain name is the generated dispatch thunk ( |
A C++ body for a | Declare it and stop | UHT generates the body ( |
| Add | UHT error "BlueprintReadWrite should not be used on private members" |
| | UHT error "Invalid BlueprintType enum base - currently only uint8 supported" |
| Wrap the inner container in a | |
| Check | |
| | |
| 请勿使用 | 5.8版本中请使用 | 来源 |
|---|---|---|
| | |
| | |
| | |
| | |
对Blueprint实现者使用 | | Blueprint实现者没有 |
调用 | | 原始名称对应的是生成的调度转接函数( |
为 | 仅声明即可,无需实现 | UHT会生成实现体( |
在私有成员上使用 | 添加 | UHT错误「BlueprintReadWrite should not be used on private members」 |
| | UHT错误「Invalid BlueprintType enum base - currently only uint8 supported」 |
| 将内层容器包装在 | |
没有 | 先检查 | |
未注册就返回 | 调用 | |
Common Mistakes
常见错误 {#common-mistakes}
BlueprintNativeEvent_ImplementationBlueprintImplementableEventvirtual void Foo_Implementation(...)BlueprintPureBlueprintCallableA non-const reference parameter that was meant as an input:
cpp
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 inputA library function that needs the world but declares no : returns null on a CDO. Take , tag it and resolve with .
WorldContextGetWorld()UBlueprintFunctionLibraryconst UObject* WorldContextObjectmeta=(WorldContext="WorldContextObject")GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)BlueprintReadWritemeta=(AllowPrivateAccess="true")Nested containers in a : UHT rejects and . Wrap the inner container in a .
UPROPERTYTArray<TArray<T>>TMap<K, TArray<V>>USTRUCT(BlueprintType)A latent action added without the UUID guard: re-entering the node stacks duplicate actions and the completion pin fires once per copy. Check first.
FindExistingAction<FMyWaitAction>(LatentInfo.CallbackTarget, LatentInfo.UUID)An async action collected mid-flight: an action that never calls lives only for the frame it was created on, so a delegate firing later never reaches it. Register in the factory and call exactly once when finished.
RegisterWithGameInstanceSetReadyToDestroy()Cast<IMyInterface>(Obj)Obj->Implements<UMyInterface>()IMyInterface::Execute_Foo(Obj, …)A static async factory without : Blueprint offers both the proxy node and a bare call to the factory, and the bare call returns an object nothing ever activates.
meta=(BlueprintInternalUseOnly="true")BlueprintNativeEvent_ImplementationBlueprintImplementableEventvirtual void Foo_Implementation(...)BlueprintPureBlueprintCallable本应作为输入的非常量引用参数:
cpp
static void Scale(FVector& Value, double Factor); // 错误:Value变成了输出引脚
static void Scale(UPARAM(ref) FVector& Value, double Factor); // 正确:按引用传递的输入
static void Scale(const FVector& Value, double Factor); // 正确:普通输入需要获取World的库函数没有声明: 在的CDO上调用会返回null。请接收参数,添加标记,并通过来获取World。
WorldContextUBlueprintFunctionLibraryGetWorld()const UObject* WorldContextObjectmeta=(WorldContext="WorldContextObject")GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)在私有成员上使用: 这是UHT错误,而非警告。请添加。
BlueprintReadWritemeta=(AllowPrivateAccess="true")UPROPERTYTArray<TArray<T>>TMap<K, TArray<V>>USTRUCT(BlueprintType)添加latent动作时没有UUID保护: 重复进入节点会堆叠重复的动作,导致完成引脚触发多次。请先检查。
FindExistingAction<FMyWaitAction>(LatentInfo.CallbackTarget, LatentInfo.UUID)异步动作在执行过程中被回收: 从未调用的动作仅在创建它的那一帧存活,因此之后触发的委托无法找到它。请在工厂函数中注册,并在完成时恰好调用一次。
RegisterWithGameInstanceSetReadyToDestroy()对Blueprint实现者使用: 会返回null,调用被静默跳过。请使用进行判断,并通过进行调用。
Cast<IMyInterface>(Obj)Obj->Implements<UMyInterface>()IMyInterface::Execute_Foo(Obj, …)静态异步工厂函数没有标记: Blueprint会同时显示代理节点和直接调用工厂函数的选项,而直接调用返回的对象永远不会被激活。
meta=(BlueprintInternalUseOnly="true")Related Skills
相关技能 {#related-skills}
- —
ue-cpp-foundations/UCLASS/UPROPERTYfundamentals, containers, delegates, subsystem lifetimes, GCUFUNCTION - — Actor and component lifecycle, spawning,
ue-actor-component-architectureBlueprintSpawnableComponent - — GameMode, PlayerController, damage, the classes Blueprint most often extends
ue-gameplay-framework - — details customization, editor utility widgets, asset actions, editor subsystems
ue-editor-tools - —
ue-async-threading,AsyncTask, timers and thread safety behind an async nodeUE::Tasks - —
ue-data-assets-tables, DataTable rows, soft references and Asset Manager loadingUDataAsset - —
ue-ui-umg-slateC++ bases,UUserWidget, exposing widget data to BlueprintBindWidget
- ——
ue-cpp-foundations/UCLASS/UPROPERTY基础、容器、委托、子系统生命周期、GCUFUNCTION - —— Actor与组件生命周期、生成、
ue-actor-component-architectureBlueprintSpawnableComponent - —— GameMode、PlayerController、伤害系统、Blueprint最常扩展的类
ue-gameplay-framework - —— 详情面板自定义、编辑器工具控件、资产操作、编辑器子系统
ue-editor-tools - ——
ue-async-threading、AsyncTask、定时器以及异步节点背后的线程安全UE::Tasks - ——
ue-data-assets-tables、DataTable行、软引用以及资源管理器加载UDataAsset - ——
ue-ui-umg-slateC++基类、UUserWidget、将控件数据暴露给BlueprintBindWidget