소스 정보
- 저장소
- kevinpbuckley/unreal-engine-skills
- 최근 소스 활동
- 2026년 8월 4일 15:34
- 감지된 SKILL.md 언어
- 영어
- 스타
- 28
- 포크
- 3
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/kevinpbuckley/unreal-engine-skills --skill umg-and-slate명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| 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:1582-1586.
| 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:
;
;
};
// 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, , ));
}
}
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:1819); 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.8). |
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:95) 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:33).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:1771,
ComputeDesiredSize:774, GetChildren:899).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).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.8, under Engine/Source/):
Runtime/UMG/Public/Blueprint/UserWidget.h — UUserWidget UCLASS:280,
AddToViewport:342, AddToPlayerScreen:351, RemoveFromViewport (deprecated 5.1):358,
NativeOnInitialized:1582, NativePreConstruct:1583, NativeConstruct:1584,
NativeDestruct:1585, NativeTick:1586, CreateWidgetInstance (backing CreateWidget):1470-1474,
EWidgetTickFrequency:117.Runtime/UMG/Public/Blueprint/WidgetTree.h — UWidgetTree, RootWidget:150,
ConstructWidget<T>:106, ForEachWidget:78, FindWidget:34.Runtime/UMG/Public/Components/Widget.h — UWidget UCLASS:216,
BindWidget/BindWidgetOptional metadata enum:69-74.Runtime/UMG/Public/Components/Button.h — UButton:32, OnClicked delegate:76,
OnPressed:80, OnReleased:84, SetStyle:117, GetStyle:119.Runtime/UMG/Public/Components/TextBlock.h — UTextBlock:23, SetText/GetText (via
Getter/Setter specifiers):31.Runtime/UMG/Public/Components/PanelWidget.h — UPanelWidget:14, AddChild:59,
GetChildAt:36, GetChildrenCount:28.Runtime/UMG/Public/Components/WidgetComponent.h — UWidgetComponent:95,
EWidgetSpace:25, GetWidget:207, SetWidget:214, SetWidgetClass:338.Runtime/SlateCore/Public/Widgets/SWidget.h — SWidget, ComputeDesiredSize:774,
GetChildren:899, OnPaint:1771.Runtime/SlateCore/Public/Widgets/SCompoundWidget.h — SCompoundWidget:21, :113.Official docs (UE 5.8, 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.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:117).ChildSlotRuntime/SlateCore/Public/Widgets/DeclarativeSyntaxSupport.h — SNew:37, SAssignNew:41.Engine/Plugins/Runtime/CommonUI/Source/CommonUI/Public/CommonUserWidget.h —
UCommonUserWidget:33.Engine/Plugins/Runtime/CommonUI/Source/CommonUI/Public/CommonActivatableWidget.h —
UCommonActivatableWidget:43, ActivateWidget:52, DeactivateWidget:55.