一键导入
umg-and-slate
Build game UI in Unreal — UMG user widgets (UUserWidget) with the C++ lifecycle
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Build game UI in Unreal — UMG user widgets (UUserWidget) with the C++ lifecycle
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Wire up callbacks and events in Unreal C++ using delegates — single-cast (DECLARE_DELEGATE, DECLARE_DELEGATE_RetVal, payload variables), multicast (DECLARE_MULTICAST_DELEGATE, DECLARE_TS_MULTICAST_DELEGATE), and dynamic (DECLARE_DYNAMIC_MULTICAST_DELEGATE, BlueprintAssignable, AddDynamic, RemoveDynamic). Covers all binding forms (BindUObject, AddUObject, BindLambda, AddWeakLambda, BindRaw, AddSP), execution (Execute, ExecuteIfBound, Broadcast), FDelegateHandle lifetime management, safe unbinding, and DECLARE_EVENT. Use when implementing the observer pattern, exposing C++ events to Blueprints, decoupling game systems, binding overlap/hit/ability callbacks, or debugging delegate crashes and silent no-ops.
Build and compose gameplay objects from Actors and Components in Unreal C++ — the AActor lifecycle (constructor, PostInitializeComponents, BeginPlay, Tick, EndPlay, Destroyed), the component types (UActorComponent, USceneComponent, UPrimitiveComponent), the root component and attachment, spawning actors and creating/registering components at construction or runtime, and ticking. Use when creating an actor or component, setting up a component hierarchy, attaching components, spawning actors, registering runtime components, or debugging lifecycle/ticking/ attachment/overlap issues.
Build AI in Unreal — AIController-driven pawns, Behavior Trees and Blackboards (tasks, decorators, services), the navigation system and NavMesh (MoveTo pathfinding, NavMeshBoundsVolume, NavAreas, avoidance), the Environment Query System (EQS generators, tests, C++ FEnvQueryRequest), AI Perception (sight/hearing/damage senses, ConfigureSense, OnTargetPerceptionUpdated), and StateTree (UStateTreeAIComponent). Use when creating enemy/NPC behavior, pathfinding/movement to targets, decision-making logic, environment queries for cover/flanking/positions, sensing the player, or replacing Behavior Trees with StateTree.
Animate skeletal meshes in Unreal using the AnimInstance / Animation Blueprint model — C++ UAnimInstance base class (NativeInitializeAnimation, NativeUpdateAnimation, NativeThreadSafeUpdateAnimation), AnimGraph with state machines and blend spaces, animation assets (UAnimSequence, UBlendSpace, UAnimMontage, UAnimComposite, UPoseAsset), anim notifies and notify states, montage playback and delegates, linked anim layers, Motion Matching (Pose Search plugin), and Motion Warping. Use when setting up character animation, driving locomotion blends from C++, playing montages for actions, firing gameplay events at precise animation frames (notifies), switching animation sets at runtime, or integrating the Pose Search / Motion Warping plugins.
Reference and load Unreal assets correctly — hard vs soft references (TObjectPtr vs TSoftObjectPtr/TSoftClassPtr), virtual content paths, FSoftObjectPath, async loading with FStreamableManager and FStreamableHandle, the Asset Registry for querying without loading, ConstructorHelpers::FObjectFinder, UAssetManager/primary data assets, and asset bundles. Use when choosing a reference type, fixing load hitches or cook/memory bloat from hard references, loading assets on demand (level streaming, DLC, runtime content), enumerating or filtering assets without loading, or setting up a managed primary-asset pipeline with UPrimaryDataAsset.
Play and control audio in Unreal — the sound asset types (SoundWave, SoundCue, MetaSound Source), playing 2D/3D sounds from C++ (UGameplayStatics, UAudioComponent), spatial attenuation, sound classes/submixes/concurrency for mixing, runtime MetaSound parameters, Quartz beat-quantized playback, and the MetaSound Builder API. Use when playing SFX/music, attaching looping sounds to actors, setting up 3D spatialization, mixing/ducking audio, driving procedural audio with MetaSounds, or debugging silent sounds, voice spam, or parameter mismatches.
| name | umg-and-slate |
| description | Build game UI in Unreal — UMG user widgets (UUserWidget) with the C++ lifecycle |
UMG is Unreal's widget-based UI framework: a Widget Blueprint pairs with a C++
UUserWidget subclass that holds logic, while the Blueprint handles layout and styling.
Underneath sits Slate, the lower-level C++ UI framework. Prefer UMG for game UI and
CommonUI for anything with menus or multiplatform input routing.
UWidgetComponent).UUserWidget — the C++ base for every Widget Blueprint. Holds logic, references to
child widgets, and lifecycle callbacks.UWidgetTree (WidgetTree.h) owns all UWidget instances that make up
the layout of a UUserWidget.UWidget (Widget.h) — base of all UMG leaf and panel widgets; wraps a Slate SWidget.SWidget (SlateCore) → SCompoundWidget →
specialized widgets. UMG wraps Slate; you only author Slate for editor tools or bespoke widgets.Declare in UserWidget.h:1574-1578.
| Callback | When | Put here |
|---|---|---|
NativeOnInitialized() | Once, after the widget object is constructed and the widget tree is built — before it is ever shown. | One-time setup that does not need a world (register non-world delegates, cache sub-widget refs). |
NativePreConstruct() | Every time the Widget Blueprint CDO is compiled or the designer refreshes. | Design-time preview work only. |
NativeConstruct() | Widget is added to the viewport / displayed — analogous to BeginPlay. | Bind OnClicked, start timers, fetch game state. |
NativeDestruct() | Widget is removed from the viewport. | Clean up delegates/timers. |
NativeTick(Geometry, DeltaTime) | Per frame — only if tick is needed. | Per-frame updates (prefer push-based updates instead). |
UUserWidget has meta=(DisableNativeTick) on its UCLASS by default; override
NativeTick only when genuinely needed or enable ticking explicitly.
meta=(BindWidget) tells UMG that a UPROPERTY in C++ maps to a widget of the same name
in the Widget Blueprint. The Blueprint compiler validates the name match at load time.
// MyHUDWidget.h
#pragma once
#include "Blueprint/UserWidget.h"
#include "MyHUDWidget.generated.h"
class UButton;
class UTextBlock;
class UProgressBar;
UCLASS()
class MYGAME_API UMyHUDWidget : public UUserWidget
{
GENERATED_BODY()
protected:
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
// Name in BP designer must match exactly:
UPROPERTY(meta=(BindWidget))
TObjectPtr<UButton> StartButton; // required — compile error if absent in BP
UPROPERTY(meta=(BindWidget))
TObjectPtr<UTextBlock> ScoreText;
UPROPERTY(meta=(BindWidgetOptional))
TObjectPtr<UProgressBar> HealthBar; // optional — null if not in BP, no error
// Bound anim (Blueprint-authored UMG animation):
UPROPERTY(meta=(BindWidgetAnim), Transient)
TObjectPtr<UWidgetAnimation> FadeInAnim;
UFUNCTION()
void OnStartClicked();
public:
void SetScore(int32 Score);
void SetHealthPercent(float Percent); // 0..1
};
// MyHUDWidget.cpp
#include "MyHUDWidget.h"
#include "Components/Button.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
void UMyHUDWidget::NativeConstruct()
{
Super::NativeConstruct();
if (StartButton)
{
StartButton->OnClicked.AddDynamic(this, &UMyHUDWidget::OnStartClicked);
}
}
void UMyHUDWidget::NativeDestruct()
{
if (StartButton)
{
StartButton->OnClicked.RemoveDynamic(this, &UMyHUDWidget::OnStartClicked);
}
Super::NativeDestruct();
}
void UMyHUDWidget::OnStartClicked()
{
// handle click
}
void UMyHUDWidget::SetScore(int32 Score)
{
if (ScoreText)
{
ScoreText->SetText(FText::AsNumber(Score)); // FText for display/localization
}
}
void UMyHUDWidget::SetHealthPercent(float Percent)
{
if (HealthBar)
{
HealthBar->SetPercent(FMath::Clamp(Percent, 0.f, 1.f));
}
}
Key rules:
BindWidgetOptional if the widget may not exist).OnClicked is a UPROPERTY(BlueprintAssignable) dynamic multicast delegate on UButton
(Button.h:76); the bound function must be a UFUNCTION().AddDynamic bindings in NativeDestruct to prevent stale delegates.// In a PlayerController or HUD:
UPROPERTY(EditAnywhere, Category="UI")
TSubclassOf<UMyHUDWidget> HUDWidgetClass; // assign the Widget BP in the editor
UPROPERTY()
TObjectPtr<UMyHUDWidget> HUDWidget;
void AMyPlayerController::BeginPlay()
{
Super::BeginPlay();
// CreateWidget<T>(owner, class) — owner can be World, PlayerController, or GameInstance
HUDWidget = CreateWidget<UMyHUDWidget>(this, HUDWidgetClass);
if (HUDWidget)
{
HUDWidget->AddToViewport(); // ZOrder 0 by default
// HUDWidget->AddToPlayerScreen(); // split-screen: add to a player's viewport slice
}
}
void AMyPlayerController::HideHUD()
{
if (HUDWidget)
{
HUDWidget->RemoveFromParent(); // hides; does not destroy (still held by UPROPERTY)
}
}
CreateWidget is a templated free function (UserWidget.h:1811); it accepts a UWorld*,
APlayerController*, UGameInstance*, UWidget*, or UWidgetTree* as owner.UPROPERTY() — without it the GC destroys the widget even if it
is displayed (memory-and-gc).RemoveFromViewport is deprecated since 5.1; use RemoveFromParent() instead.| Approach | When |
|---|---|
| Push setters (recommended) | Call SetScore()/SetHealthPercent() from gameplay code when data changes — zero per-frame cost. |
| UMG Property Binding (legacy) | A function returning a value bound in the editor; re-evaluates every frame — avoid for many widgets. |
| MVVM Viewmodel plugin | Declare UMVVMViewModelBase with FieldNotify properties; view bindings update only on change. Best for larger data-driven UIs (UE 5.1+, still Beta in 5.7). |
Epic's hard rule: never raw property bindings — they poll every frame per widget.
Drive updates from gameplay delegates, and pull initial state once in NativeConstruct.
Full MVVM walkthrough (FieldNotify, UE_MVVM_SET_PROPERTY_VALUE, viewmodel design):
references/architecture-and-authoring.md.
The rules agents most often need — deep dive with engine citations in references/performance-and-best-practices.md:
Overlay/HorizontalBox/VerticalBox/GridPanel.UInvalidationBox; mark per-frame widgets
Volatile; reach for URetainerBox (phased render-to-texture) only after that.UListView/UTileView (virtualized + pooled) for lists,
FUserWidgetPool for damage numbers/markers/toasts.WidgetSwitcher page, every
TSubclassOf reference. Delete unused widgets; async-load rare screens via soft refs.Collapsed over Hidden (skips layout); set decorative widgets to
HitTestInvisible; don't call SetVisibility/FText::Format per frame.USpacer over USizeBox for spacing; never Scale Box + Size Box together
(per-frame layout flip-flop); Rich Text only when really needed.stat Slate, Widget Reflector (Ctrl+Shift+W), Slate.ShowBatching,
stat dumpframe -ms=0.1.NativeOnKeyDown, NativeOnMouseButtonDown, etc. for per-widget input handling.PlayerController via
SetInputModeUIOnly/SetInputModeGameAndUI/SetInputModeGameOnly and toggle the cursor.UWidgetComponent (WidgetComponent.h:94) is a UMeshComponent that renders a
UUserWidget onto a render target, then displays it on a plane or cylinder in 3D space.
// In an actor's .h:
UPROPERTY(VisibleAnywhere)
TObjectPtr<UWidgetComponent> InteractPrompt;
// In constructor:
InteractPrompt = CreateDefaultSubobject<UWidgetComponent>(TEXT("InteractPrompt"));
InteractPrompt->SetupAttachment(RootComponent);
InteractPrompt->SetWidgetClass(PromptWidgetClass); // TSubclassOf<UUserWidget>
InteractPrompt->SetDrawSize(FVector2D(200.f, 80.f));
InteractPrompt->SetWidgetSpace(EWidgetSpace::World); // World or Screen
Access the live widget instance at runtime: InteractPrompt->GetWidget().
For player interaction with 3D widgets, pair with UWidgetInteractionComponent.
The CommonUI plugin (Engine/Plugins/Runtime/CommonUI/) builds on UMG for structured,
multiplatform UI:
UCommonUserWidget — UUserWidget + input-action binding (CommonUserWidget.h:21).UCommonActivatableWidget — adds activate/deactivate semantics and a back-navigation
stack; the widget can turn on/off without being removed from the hierarchy
(CommonActivatableWidget.h:43).UCommonButtonBase, UCommonTextBlock, etc., separate style data from
widget instances, making platform-specific theming practical.Use CommonUI for any UI with menus, modals, or gamepad navigation. Base game-HUD widgets
on UCommonUserWidget; base menus on UCommonActivatableWidget.
Screen architecture — layer stacks (the Lyra pattern): production games register one
root layout with named layers, each a UCommonActivatableWidgetStack (or ...Queue for
modals) — e.g. UI.Layer.Game / GameMenu / Menu / Modal in Lyra's
PrimaryGameLayout. Screens are pushed/popped by layer tag instead of AddToViewport,
which gives correct Z-order, input routing to the topmost active widget, and free
back-button handling. Details and best practices:
references/architecture-and-authoring.md.
UMG wraps Slate. For editor tools and highly bespoke widgets not achievable in UMG, author Slate directly.
// Minimal SCompoundWidget subclass — editor tool or plugin UI:
class SMyPanel : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SMyPanel) {}
SLATE_ARGUMENT(FText, LabelText)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs)
{
ChildSlot
[
SNew(STextBlock).Text(InArgs._LabelText)
];
}
};
Core Slate types:
SWidget (SlateCore/Public/Widgets/SWidget.h) — base; pure abstract (OnPaint:1650,
ComputeDesiredSize:731, GetChildren:856).SCompoundWidget (SCompoundWidget.h) — single ChildSlot; base for most authored widgets.SLeafWidget — no children; for custom-drawn leaf elements.SNew(WidgetType) / SAssignNew(Ptr, WidgetType) — declarative construction macros
(DeclarativeSyntaxSupport.h:37).For game UI, stay in UMG/CommonUI — Slate skips UPROPERTY/GC and needs more boilerplate.
BindWidget name mismatch — the C++ variable name must match the Blueprint widget name
exactly; a mismatch is a compiler/load error. Use BindWidgetOptional if the widget may be
absent. (Widget.h:69-74).UPROPERTY — the GC destroys it even if still displayed; always hold
in a UPROPERTY() member.RemoveFromViewport deprecated (5.1+) — use RemoveFromParent().SetVisibility every frame — it's surprisingly expensive (can invalidate
layout); only call on actual state change. Prefer Collapsed over Hidden, and
HitTestInvisible for decorations.WidgetSwitcher pay full load/construct cost; delete leftovers, async-load rare
screens.UListView or FUserWidgetPool
instead; with FUserWidgetPool, call ReleaseAllSlateResources() from the owner's
ReleaseSlateResources or the pool leaks via circular refs.OnClicked handler not a UFUNCTION() — AddDynamic silently fails; the bound method
must be marked UFUNCTION() with the matching signature.SetInputMode/cursor — menus added to viewport that don't receive clicks
usually have the wrong input mode on the owning PlayerController.enhanced-input for input-action integration).FString — use FText::AsNumber, FText::Format, etc. for
localization (core-types-and-containers).WidgetComponent not visible — ensure DrawSize is non-zero and collision/visibility
settings are correct; EWidgetSpace::Screen ignores world occlusion.NativeTick never called — UUserWidget has DisableNativeTick by default; the tick
only runs if you override NativeTick and the widget has latent actions or Blueprint tick
is set to Auto (EWidgetTickFrequency:UserWidget.h:120).RemoveFromViewport deprecated in 5.1; replaced by RemoveFromParent (from UWidget).UTextBlock/UButton direct property access deprecated in 5.1/5.2 respectively; use
getter/setter methods (GetText()/SetText(), GetStyle()/SetStyle()).Engine source (UE 5.7, under Engine/Source/):
Runtime/UMG/Public/Blueprint/UserWidget.h — UUserWidget UCLASS:282,
AddToViewport:345, AddToPlayerScreen:354, RemoveFromViewport (deprecated 5.1):359,
NativeOnInitialized:1574, NativePreConstruct:1575, NativeConstruct:1576,
NativeDestruct:1577, NativeTick:1578, CreateWidgetInstance (backing CreateWidget):1462-1466,
EWidgetTickFrequency:120.Runtime/UMG/Public/Blueprint/WidgetTree.h — UWidgetTree, RootWidget:142,
ConstructWidget<T>:102, ForEachWidget:74, FindWidget:30.Runtime/UMG/Public/Components/Widget.h — UWidget UCLASS:215,
BindWidget/BindWidgetOptional metadata enum:68-74.Runtime/UMG/Public/Components/Button.h — UButton:32, OnClicked delegate:76,
OnPressed:80, OnReleased:83, SetStyle:117, GetStyle:119.Runtime/UMG/Public/Components/TextBlock.h — UTextBlock:22, SetText/GetText (via
Getter/Setter specifiers):30.Runtime/UMG/Public/Components/PanelWidget.h — UPanelWidget:14, AddChild:59,
GetChildAt:36, GetChildrenCount:28.Runtime/UMG/Public/Components/WidgetComponent.h — UWidgetComponent:94,
EWidgetSpace:24, GetWidget:206, SetWidget:213, SetWidgetClass:337.Runtime/SlateCore/Public/Widgets/SWidget.h — SWidget, ComputeDesiredSize:731,
GetChildren:856, OnPaint:1650.Runtime/SlateCore/Public/Widgets/SCompoundWidget.h — SCompoundWidget:21, ChildSlot:113.Runtime/SlateCore/Public/Widgets/DeclarativeSyntaxSupport.h — SNew:37, SAssignNew:41.Engine/Plugins/Runtime/CommonUI/Source/CommonUI/Public/CommonUserWidget.h —
UCommonUserWidget:21.Engine/Plugins/Runtime/CommonUI/Source/CommonUI/Public/CommonActivatableWidget.h —
UCommonActivatableWidget:43, ActivateWidget:52, DeactivateWidget:55.Official docs (UE 5.7, verified):
Deep-dive references in this skill:
UUserWidget lifecycle, BindWidget internals, NativeOnInitialized vs NativeConstruct,
animation binding (BindWidgetAnim), and GameViewportSubsystem.UWidgetComponent deep dive, UWidgetInteractionComponent, input mode management, focus.SWidget hierarchy, declarative
syntax, SCompoundWidget authoring, Invalidation, and when to use Slate vs UMG.FUserWidgetPool, ListView), loading/construction costs, Canvas Panel
and layout do/don'ts, animation cost tiers, hidden costs (SetVisibility,
FText::Format), and the profiling toolbox.FieldNotify, UE_MVVM_SET_PROPERTY_VALUE), DPI scaling and
resolution independence, safe zones, and texture/slot-sizing authoring rules.