mcpField
U
ue-ui-umg-slate

ue-ui-umg-slate

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

ue-ui-umg-slate について

UMG、Slate、Common UI を使う Unreal Engine 5.8 の UI 開発向けスキルガイドです。ウィジェットのライフサイクル、操作、アニメーション、入力フォーカス、リスト、MVVM を扱います。

主な機能

  1. 01ウィジェットのライフサイクルと作成
  2. 02UMG の操作とリスト
  3. 03ウィジェットアニメーションと入力フォーカス
  4. 04Common UI のアクティベーションスタックと入力ルーティング
  5. 05Slate と MVVM のガイド

活用シーン

  1. 01ランタイムウィジェットの作成と管理
  2. 02ボタンのバインドとテキストや進捗の表示
  3. 03メニュー画面とアクティベーションスタックの構築
  4. 04データバインディングやカスタム Slate ウィジェットの実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/quodsoler/unreal-engine-skills --skill ue-ui-umg-slate

インストール後、Claude Code で/ue-ui-umg-slateを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
common-ui-setup.md
slate-patterns.md
widget-types.md

詳細

UE UI:UMG、Slate、Common UI

対象エンジン:UE 5.8。以下の API は 5.8 のヘッダーに照らして確認済みです。古い形式は「非推奨 — 使用しないでください」に記載しています。

UMG は Slate(Slate、SlateCore)上に構築されたランタイム UI フレームワーク(UMG モジュール、Engine/Source/Runtime/UMG/Public)です。Common UI(プラグイン、5.8 で本番利用可能)は、クロスプラットフォームの入力ルーティング、アクティベーションスタック、プラットフォーム対応ボタンを追加します。Model View Viewmodel(プラグイン、5.8 でベータ)は、FieldNotification 上に宣言的なデータバインディングを追加します。

コンテキスト

.agents/ue-project-context.md が存在する場合は読み込んでください(モジュール名、規約、有効なプラグイン、GAS/ネットワーク設定)。ファイルがない場合も作業を中断しないでください。

依頼内容とコードベースから該当領域を特定してください。妥当な解釈が 2 通りあり、それぞれで異なるコードになる場合に限り、確認してください。

依頼の内容…参照先
ウィジェットクラス、オーバーライド、作成、可視性、GCウィジェットのライフサイクル
デザイナーのウィジェットを C++ に接続する(meta=(BindWidget))BindWidget
ボタン、テキスト、画像、バー、リストウィジェットの操作
UMG アニメーションの再生/停止ウィジェットアニメーション
マウスカーソル、フォーカス、SetInputMode入力モードとフォーカス
メニュー、画面スタック、ゲームパッド、戻る操作Common UI
データバインディング、ビューモデル、フィールド通知MVVM
レベル内に描画される UIワールド空間 UI
ウィジェットの反復処理、ドラッグ&ドロップ、ブラシ、ジオメトリウィジェットツリーとヘルパーライブラリ
カスタム SWidget、SNew、SLATE_BEGIN_ARGSSlate

ウィジェットごとのメソッド一覧(セッター、デリゲート、列挙型)は references/widget-types.md にあります。Common UI プラグインのセットアップ全体は references/common-ui-setup.md にあります。カスタム Slate ウィジェットの完全な例は references/slate-patterns.md にあります。

ウィジェットのライフサイクル

// MyWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "MyWidget.generated.h"

class UButton;

UCLASS()
class MYGAME_API UMyWidget : public UUserWidget
{
    GENERATED_BODY()

protected:
    virtual void NativeOnInitialized() override;
    virtual void NativePreConstruct() override;
    virtual void NativeConstruct() override;
    virtual void NativeDestruct() override;
    virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;

    UPROPERTY(meta=(BindWidget))
    TObjectPtr<UButton> PlayButton;

    UFUNCTION()
    void HandlePlayClicked();
};

// MyWidget.cpp — #include "MyWidget.h" and "Components/Button.h"
void UMyWidget::NativeOnInitialized() { Super::NativeOnInitialized(); }
void UMyWidget::NativePreConstruct() { Super::NativePreConstruct(); }
void UMyWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
    Super::NativeTick(MyGeometry, InDeltaTime);
}

void UMyWidget::NativeConstruct()
{
    Super::NativeConstruct();       // Runs on every re-add; pair each bind with an unbind in NativeDestruct
    PlayButton->OnClicked.AddDynamic(this, &UMyWidget::HandlePlayClicked);
}

void UMyWidget::NativeDestruct()
{
    PlayButton->OnClicked.RemoveDynamic(this, &UMyWidget::HandlePlayClicked);
    Super::NativeDestruct();
}
オーバーライド(Blueprint/UserWidget.h の記述どおり)実行タイミング
virtual void NativeOnInitialized() override;インスタンスごとに 1 回、ウィジェットオブジェクトの構築後
virtual void NativePreConstruct() override;Slate ツリーの再構築後、NativeConstruct の直前(UserWidget.cpp:1231)。デザイナーでも実行されます
virtual void NativeConstruct() override;Slate ウィジェットが親に追加されたとき — ここでデリゲートをバインドします
virtual void NativeDestruct() override;Slate ウィジェットが削除されたとき — ここでバインドを解除します
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;ティック中、毎フレーム
virtual int32 NativePaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;カスタム描画。最後に使用したレイヤー ID を返します
virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;ポインターが押されたとき
virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override;フォーカス中にキーが押されたとき
virtual FReply NativeOnFocusReceived(const FGeometry& InGeometry, const FFocusEvent& InFocusEvent) override;このウィジェットがフォーカスを得たとき
virtual void NativeOnAddedToFocusPath(const FFocusEvent& InFocusEvent) override;このウィジェットまたは子孫がフォーカスを得たとき
virtual bool Initialize() override;ウィジェットツリーを構築します。Super::Initialize() を呼び、その結果を返します
virtual TSharedRef<SWidget> RebuildWidget() override;基盤となる Slate ウィジェットを構築します
virtual void ReleaseSlateResources(bool bReleaseChildren) override;キャッシュ済みの TSharedPtr<SWidget> メンバーをここで解放します

入力ハンドラーは、イベントを処理する場合は FReply::Handled() を返し、イベントを上位に伝播させる場合は FReply::Unhandled() を返します。

作成、ビューポート、表示状態
// CreateWidget<T>(Owner, Class, WidgetName = NAME_None). Owner may be a UWidget,
// UWidgetTree, APlayerController, UGameInstance or UWorld.
UMyWidget* Widget = CreateWidget<UMyWidget>(GetOwningPlayer(), MyWidgetClass);
Widget->AddToViewport(0);       // ZOrder: higher draws on top. Roots the widget.
Widget->AddToPlayerScreen(0);   // Split-screen: one player's viewport region; returns bool
Widget->RemoveFromParent();     // Un-roots - collectable unless a UPROPERTY holds it
Widget->SetVisibility(ESlateVisibility::Collapsed);  // Not drawn, takes no space
Widget->SetVisibility(ESlateVisibility::Hidden);     // Not drawn, still takes space
Widget->SetVisibility(ESlateVisibility::Visible);    // Drawn, hit-testable
Widget->SetIsEnabled(false);                         // Greys out, blocks input

HitTestInvisibleは描画しますが、ウィジェットとその子ウィジェットへの入力を通過させます。SelfHitTestInvisibleはウィジェット自体への入力のみを通過させます。ウィジェットをRemoveFromParent後も存続させる必要がある場合は、UPROPERTY() TObjectPtr<UMyWidget>を保持します。GetOwningPlayer()は所有元のAPlayerControllerを返し、GetOwningPlayer<AMyPlayerController>()はキャストも行います。

BindWidget

UPROPERTY(meta=(BindWidget))                 // Compile error in the Widget BP if missing
TObjectPtr<UTextBlock> ScoreText;
UPROPERTY(meta=(BindWidgetOptional))         // May be null - always null-check
TObjectPtr<UTextBlock> SubtitleText;
UPROPERTY(Transient, meta=(BindWidgetAnim))  // Transient is required for animation bindings
TObjectPtr<UWidgetAnimation> IntroAnim;

ルール:C++メンバー名はWidget Blueprintのウィジェット名と完全に一致する必要があります(大文字と小文字を区別)。宣言する型は、デザイナーウィジェットのクラスと一致するか、その基底クラスである必要があります。バインドされたメンバーはInitialize()内でNativeOnInitializedの実行前に割り当てられるため(UserWidget.cpp:153,175)、NativeOnInitialized、NativePreConstruct、NativeConstructで有効です。インスタンスごとに一度だけバインドするデリゲートはNativeOnInitializedでバインドします。Categoryを指定せず、protectedとして宣言します。

ウィジェット操作

UMGコンポーネントの動的マルチキャストデリゲートにはAddDynamicを使用するため、ハンドラーはUFUNCTION()である必要があります。

PlayButton->OnClicked.AddDynamic(this, &UMyWidget::HandlePlayClicked);
PlayButton->SetColorAndOpacity(FLinearColor(1.f, 0.8f, 0.f, 1.f));
ScoreText->SetText(FText::Format(NSLOCTEXT("HUD", "ScoreFmt", "Score: {0}"), FText::AsNumber(Score)));
ScoreText->SetTextOverflowPolicy(ETextOverflowPolicy::Ellipsis);
PlayerAvatar->SetBrushFromSoftTexture(SoftAvatarTexture, /*bMatchSize=*/false);
UMaterialInstanceDynamic* AvatarMID = PlayerAvatar->GetDynamicMaterial();
AvatarMID->SetScalarParameterValue(TEXT("Opacity"), 0.5f);
HealthBar->SetPercent(CurrentHealth / MaxHealth);   // 0.0-1.0
HealthBar->SetFillColorAndOpacity(FLinearColor(0.f, 1.f, 0.f, 1.f));

UButton、UTextBlock、UImage、UProgressBar、UScrollBox、UWidgetSwitcher、UCheckBox、UEditableTextBox、USlider、UComboBoxStringおよびUWidget基底クラスのメソッドと列挙型の一覧は、references/widget-types.mdにあります。

リスト:UListView、UTileView、UTreeView

これら3つはすべて仮想化されており、表示中のエントリーウィジェットのみが存在し、再利用されます。アイテムはUObject*です。エントリーウィジェットはUUserWidgetを継承し、IUserObjectListEntryを実装して、virtual void NativeOnListItemObjectSet(UObject* ListItemObject) override;をオーバーライドします(最初にIUserObjectListEntry::NativeOnListItemObjectSetを呼び出してください)。エントリーウィジェットの完全な例とUListViewメソッド一覧は、references/widget-types.mdにあります。

ItemList->ClearListItems();
for (const FMyItemInfo& Info : Items)
{
    UMyItemData* Data = NewObject<UMyItemData>(this);
    Data->DisplayName = Info.DisplayName;
    ItemList->AddItem(Data);
}
UMyItemData* Selected = ItemList->GetSelectedItem<UMyItemData>();

BP_OnItemClickedはBlueprint専用のプライベートデリゲートです。C++からは、ネイティブイベントItemList->OnItemClicked().AddUObject(...)(FSimpleListItemEvent、Components/ListViewBase.h:48。OnItemSelectionChanged()も参照)をバインドするか、UListViewのサブクラスでvirtual void OnItemClickedInternal(UObject* Item) override;をオーバーライドします。エントリーウィジェット内では、GetListItem<UMyItemData>()でアイテムを取得し、インターフェイスメンバーのIsListItemSelected()で選択状態を確認します(Blueprint/IUserListEntry.h:32)。

ウィジェットアニメーション

PlayAnimationとその派生関数はFWidgetAnimationHandleを返します(Animation/WidgetAnimationHandle.h)。シーケンスプレーヤーへのポインターではなく、このハンドルを保持してください。有効なハンドルでも、アニメーション終了後は状態を取得できない場合があるため、IsValid()を確認してください。

// PlayAnimation(UWidgetAnimation*, StartAtTime=0, NumLoopsToPlay=1,
//               EUMGSequencePlayMode::Type=Forward, PlaybackSpeed=1, bRestoreState=false)
FWidgetAnimationHandle IntroHandle = PlayAnimation(IntroAnim);
IntroHandle.SetUserTag(TEXT("Intro"));
PlayAnimationForward(IntroAnim);                        // also PlayAnimationReverse
const float PausedAt = PauseAnimation(IntroAnim);
const bool bPlaying = IsAnimationPlaying(IntroAnim);
StopAnimation(IntroAnim);

入力モードとフォーカス

入力モードとEnhanced Inputはue-input-systemが管理します。正しい最小限の形式は次のとおりです。

FInputModeUIOnly UIMode;
UIMode.SetWidgetToFocus(Widget->TakeWidget());
UIMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
GetOwningPlayer()->SetInputMode(UIMode);
GetOwningPlayer()->SetShowMouseCursor(true);
// Restore gameplay:
GetOwningPlayer()->SetInputMode(FInputModeGameOnly());
GetOwningPlayer()->SetShowMouseCursor(false);

FInputModeGameAndUIには、SetWidgetToFocusとSetLockMouseToViewportBehaviorもあります。入力モードはNativeConstructではなく、ウィジェットを追加したコード(HUD、PlayerController、GameMode)から設定してください。Common UIが有効な場合は、SetInputModeを呼び出さず、代わりにFUIInputConfigを返してください。

Common UI

CommonUI プラグイン(CommonUI と CommonInput の両モジュールを含みます)を有効にし、両方のモジュールを Build.cs に追加して、ビューポートクライアントクラスを UCommonGameViewportClient に設定します。これはゲームに入力が渡る前に、UI アクションルーターへ入力を振り分けます(CommonGameViewportClient.h:21)。ゲームパッド/マウス/タッチの変更は、UCommonInputSubsystem の FCommonInputPreprocessor によって検出され、そのサブシステムからブロードキャストされます。セットアップの詳細、レイヤーアーキテクチャ、設定キーについては、references/common-ui-setup.md を参照してください。

// MyMenuScreen.h
#pragma once
#include "CommonActivatableWidget.h"
#include "MyMenuScreen.generated.h"

class UCommonButtonBase;

UCLASS()
class MYGAME_API UMyMenuScreen : public UCommonActivatableWidget
{
    GENERATED_BODY()

protected:
    virtual void NativeOnActivated() override;
    virtual void NativeOnDeactivated() override;
    virtual UWidget* NativeGetDesiredFocusTarget() const override;
    virtual TOptional<FUIInputConfig> GetDesiredInputConfig() const override;
    virtual bool NativeOnHandleBackAction() override;   // Return true when handled

    UPROPERTY(meta=(BindWidget))
    TObjectPtr<UCommonButtonBase> CloseButton;

    void HandleCloseClicked();
};

// MyMenuScreen.cpp — #include "MyMenuScreen.h" and "CommonButtonBase.h"
void UMyMenuScreen::NativeOnActivated()
{
    Super::NativeOnActivated();     // Broadcasts OnActivated(), which activates this widget's tree node
    CloseButton->OnClicked().AddUObject(this, &UMyMenuScreen::HandleCloseClicked);
}

void UMyMenuScreen::NativeOnDeactivated()
{
    CloseButton->OnClicked().RemoveAll(this);
    Super::NativeOnDeactivated();   // Broadcasts OnDeactivated(); the router moves focus to the parent
}

UWidget* UMyMenuScreen::NativeGetDesiredFocusTarget() const { return CloseButton; }

TOptional<FUIInputConfig> UMyMenuScreen::GetDesiredInputConfig() const
{
    return FUIInputConfig(ECommonInputMode::Menu, EMouseCaptureMode::NoCapture);
}

bool UMyMenuScreen::NativeOnHandleBackAction() { DeactivateWidget(); return true; }
void UMyMenuScreen::HandleCloseClicked() { DeactivateWidget(); }

パブリック API:ActivateWidget()、DeactivateWidget()、IsActivated()、GetDesiredFocusTarget()、ClearFocusRestorationTarget()、RequestRefreshFocus()、および動的ではない OnActivated()/OnDeactivated() デリゲート。BP_GetDesiredFocusTarget は NativeGetDesiredFocusTarget が呼び出す BlueprintImplementableEvent です。C++ ではネイティブ版をオーバーライドしてください。編集可能なデフォルト値:bAutoActivate、bIsBackHandler、bIsBackActionDisplayedInActionBar、bIsModal、bAutoRestoreFocus、bSetVisibilityOnActivated/ActivatedVisibility、bSetVisibilityOnDeactivated/DeactivatedVisibility。ECommonInputMode は Menu(UI のみ)、Game(ゲームのみ)、または All です。

コンテナー

UCommonActivatableWidgetContainerBase(Widgets/CommonActivatableWidgetContainer.h)は基底クラスです。UCommonActivatableWidgetStack は最上位のウィジェットを表示し、それが非アクティブになると、その下にあるウィジェットを再アクティブ化します。UCommonActivatableWidgetQueue は一度に 1 つを表示し、アクティブなウィジェットが非アクティブになると次に進みます。UCommonActivatableWidgetSwitcher はインデックスベースのスイッチャーであり、スタックではありません。ここでは使用しないでください。

UPROPERTY(meta=(BindWidget))
TObjectPtr<UCommonActivatableWidgetStack> MenuLayer;
// AddWidget<T> creates (or pools) the instance, adds it, and the container activates it.
UMyMenuScreen* Screen = MenuLayer->AddWidget<UMyMenuScreen>(UMyMenuScreen::StaticClass());
// Overload with an init lambda that runs after creation, before the widget is added:
MenuLayer->AddWidget<UMyMenuScreen>(UMyMenuScreen::StaticClass(),
    [](UMyMenuScreen& Instance) { Instance.SetIsEnabled(true); });

if (UCommonActivatableWidget* Active = MenuLayer->GetActiveWidget())
{
    Active->DeactivateWidget();         // Pops the stack
}
// RemoveWidget(UCommonActivatableWidget&) deactivates the active widget, or yanks an inactive one
MenuLayer->RemoveWidget(*Screen);
MenuLayer->ClearWidgets();              // GetNumWidgets() reports the current depth
ボタン、入力タイプ、アクションルーティング
// UCommonButtonBase::OnClicked() returns FCommonButtonEvent (DECLARE_EVENT, no params).
MyButton->OnClicked().AddUObject(this, &UMyMenuScreen::HandleCloseClicked);
MyButton->OnClicked().RemoveAll(this);
MyButton->SetIsSelected(true);
MyButton->SetIsInteractionEnabled(true);
UCommonInputSubsystem* InputSubsystem = UCommonInputSubsystem::Get(GetOwningLocalPlayer());
const ECommonInputType InputType = InputSubsystem->GetCurrentInputType();  // MouseAndKeyboard, Gamepad, Touch
InputSubsystem->OnInputMethodChangedNative.AddUObject(this, &UMyMenuScreen::HandleInputMethodChanged);

// UCommonUIActionRouterBase is the local-player subsystem that routes input through the activation tree.
if (UCommonUIActionRouterBase* Router = UCommonUIActionRouterBase::Get(*CloseButton))
{
    const ECommonInputMode Mode = Router->GetActiveInputMode();
}

// On a UCommonUserWidget subclass, with UPROPERTY(EditDefaultsOnly) TObjectPtr<UInputAction> BackInputAction:
FUIActionBindingHandle BackHandle = RegisterUIActionBinding(
    FBindUIActionArgs(BackInputAction, /*bShouldDisplayInActionBar=*/true,
        FSimpleDelegate::CreateUObject(this, &UMyMenuScreen::HandleCloseClicked)));

OnInputMethodChangedNative は DECLARE_EVENT_OneParam なので、HandleInputMethodChanged(ECommonInputType) に UFUNCTION() は必要ありません。5.8 では Enhanced Input と Common Input が統合されています。bEnableEnhancedInputSupport を有効にすると(UCommonInputSettings::IsEnhancedInputSupportEnabled())、FBindUIActionArgs は const UInputAction* を受け取り、UCommonActivatableWidget::InputMapping/InputMappingPriority はアクティブ化時にマッピングコンテキストを適用します。

MVVM

ModelViewViewModel は 5.8 ではベータ版です。ビューモデルは UMVVMViewModelBase です。FieldNotify プロパティにはフィールド記述子が生成され、UE_MVVM_SET_PROPERTY_VALUE は 1 回の呼び出しで比較、代入、ブロードキャストを行います。

// MyGameViewModel.h
#pragma once
#include "MVVMViewModelBase.h"
#include "MyGameViewModel.generated.h"

UCLASS()
class MYGAME_API UMyGameViewModel : public UMVVMViewModelBase
{
    GENERATED_BODY()

public:
    void SetScore(int32 NewScore) { UE_MVVM_SET_PROPERTY_VALUE(Score, NewScore); }
    int32 GetScore() const { return Score; }

private:
    UPROPERTY(BlueprintReadOnly, FieldNotify, Getter, meta=(AllowPrivateAccess))
    int32 Score = 0;
};

// Binding at runtime - the UMVVMView extension on the user widget owns the generated bindings.
UMyGameViewModel* ViewModel = NewObject<UMyGameViewModel>(this);
if (UMVVMView* View = UMVVMSubsystem::GetViewFromUserWidget(MyWidget))
{
    View->SetViewModel(TEXT("ScoreViewModel"), ViewModel);   // Name from the Bindings panel
}

UE_MVVM_SET_PROPERTY_VALUE(MemberName, NewValue) は SetPropertyValue(MemberName, NewValue, ThisClass::FFieldNotificationClassDescriptor::MemberName) に展開されます。関数の引数として渡せない値(ビットフィールド)には UE_MVVM_SET_PROPERTY_VALUE_INLINE を使用し、自分でメンバーに代入した場合は UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(MemberName) を使用してください。どちらも、最終的には INotifyFieldValueChanged の BroadcastFieldValueChanged(UE::FieldNotification::FFieldId) を呼び出します。

UHT はすべての FieldNotify プロパティと関数について記述子を生成します。フィールドを手動で宣言するのは、UCLASS(CustomFieldNotify) クラス指定子(メタキーではありません。Components/Widget.h:215 を参照)を使用する場合に限ります。その際は、FieldNotificationDeclaration.h(FieldNotification モジュール。旧 FieldNotification/ パスは 5.3 以降非推奨)にある UE_FIELD_NOTIFICATION_DECLARE_CLASS_DESCRIPTOR_BEGIN/UE_FIELD_NOTIFICATION_DECLARE_FIELD(Name, API_STRING)/UE_FIELD_NOTIFICATION_DECLARE_ENUM_FIELD(Name)/..._END の各マクロと、.cpp での UE_FIELD_NOTIFICATION_IMPLEMENTATION_BEGIN および UE_FIELD_NOTIFICATION_IMPLEMENTATION_END を組み合わせてください。UMVVMView は GetViewModel(FName)、SetViewModelByClass(...)、ExecuteViewModelBindings(FName) も公開します。UMVVMSubsystem は UEngineSubsystem で、GetViewFromUserWidget は静的です。

ワールド空間 UI

UWidgetComponent(Components/WidgetComponent.h、UMG モジュール)は、レベル内の平面または円柱に UUserWidget を描画します。

// In the constructor of AMyCharacter (NameplateComponent is a UPROPERTY member):
NameplateComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("Nameplate"));
NameplateComponent->SetupAttachment(RootComponent);
NameplateComponent->SetWidgetSpace(EWidgetSpace::World);        // or EWidgetSpace::Screen
NameplateComponent->SetDrawSize(FVector2D(256.f, 64.f));
NameplateComponent->SetGeometryMode(EWidgetGeometryMode::Plane);// or Cylinder
NameplateComponent->SetTwoSided(false);
// At runtime:
NameplateComponent->SetWidget(NameplateWidget);
UUserWidget* Current = NameplateComponent->GetUserWidgetObject();
NameplateComponent->SetTickMode(ETickMode::Disabled);   // Then drive updates manually
NameplateComponent->RequestRedraw();

実際のマウス入力を受け取る必要があるウィジェットに限り、bReceiveHardwareInput を有効にしてください。それ以外の場合は、UWidgetInteractionComponent を使って操作してください。

ウィジェットツリーとヘルパーライブラリ

WidgetTree->ForEachWidget([](UWidget* Widget) { Widget->SetRenderOpacity(1.f); });
WidgetTree->ForEachWidgetAndDescendants([](UWidget* W) { W->SetIsEnabled(true); });
UButton* Found = WidgetTree->FindWidget<UButton>(TEXT("PlayButton"));
UMyEntryWidget* Built = WidgetTree->ConstructWidget<UMyEntryWidget>(EntryWidgetClass);

UWidgetBlueprintLibrary(Blueprint/WidgetBlueprintLibrary.h)には、ブラシ、ドラッグ&ドロップ、FEventReply、FPaintContext の描画ヘルパーが用意されています。USlateBlueprintLibrary(Blueprint/SlateBlueprintLibrary.h)は、ローカル空間、絶対空間、ビューポート空間の間で変換します。どちらもreferences/widget-types.mdに記載されています。

Slate

エディター拡張や、UMG では公開されていないランタイムウィジェットには Slate を使用します。SWidget が基底クラスで、カスタムウィジェットの親クラスには通常 SCompoundWidget を使用します。

カスタムウィジェットでは、SLATE_BEGIN_ARGS / SLATE_END_ARGS の間に引数を宣言します。ラムダにバインドできる TAttribute<T> には SLATE_ATTRIBUTE、通常の値には SLATE_ARGUMENT、デリゲートには SLATE_EVENT を使用します。Construct(const FArguments& InArgs) 内で、子ウィジェットを ChildSlot に組み立てます。Slate デリゲートのバインドには CreateSP を使用し、破棄されたウィジェットが呼び出されないようにします。3 種類すべての引数を使用した SCompoundWidget の完全な例は、references/slate-patterns.mdを参照してください。

SNew(WidgetType) は TSharedRef<WidgetType> を返します。SAssignNew(Var, WidgetType) も同様ですが、TSharedPtr に格納します。FOnClicked は DECLARE_DELEGATE_RetVal(FReply, FOnClicked) なので、クリックハンドラーは FReply を返す必要があります。UWidget::GetCachedWidget() は、UMG ウィジェットの背後にある TSharedPtr<SWidget> を取得します。UUserWidget::TakeWidget() は TSharedRef<SWidget> を構築して返します。

標準 Slate ウィジェットの公開 TAttribute メンバーは、プライベート化が進められています。 直接読み書きしないでください。非推奨メッセージに記載されたアクセサーを使用します。値を設定するには Set<Name>、TSlateAttributeRef を読み取るには Get<Name>Attribute() を使用してください。5.8 では、SCheckBox::PaddingOverride(SetPaddingOverride / GetPaddingOverrideAttribute)、SCheckBox::ForegroundColorOverride(SetForegroundColorOverride / GetForegroundColorOverrideAttribute)、SEditableText::Font(SetFont / GetFontAttribute)、SEditableText::ColorAndOpacity(SetColorAndOpacity / GetColorAndOpacityAttribute)、SMenuAnchor::Placement(SetMenuPlacement / GetPlacementAttribute)が対象です。

Slate と UMG: エディターツールや最大限の制御には Slate を、ゲームのランタイム UI、Blueprint による拡張性、アニメーション、BindWidget には UMG を使用します。

Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "UMG", "Slate", "SlateCore" });
PrivateDependencyModuleNames.AddRange(new string[] {
    "CommonUI", "GameplayTags", // Activatable widgets, buttons, action router, FUIInputConfig; FBindUIActionArgs' FUIActionTag links GameplayTags
    "CommonInput", "EnhancedInput", // UCommonInputSubsystem, ECommonInputType/Mode; UInputAction UPROPERTYs
    "ModelViewViewModel",  // MVVM (Beta in 5.8)
    "FieldNotification" }); // Field-notification declaration macros

非推奨 — 使用しないでください

使用しないでください5.8 で使用ソース
UUserWidget::RemoveFromViewport()RemoveFromParent()Blueprint/UserWidget.h:356 の UE_DEPRECATED(5.1)
PlayAnimation から返される UUMGSequencePlayer*FWidgetAnimationHandle / FWidgetAnimationStateAnimation/UMGSequencePlayer.h:29 の UE_DEPRECATED(5.6)
UUserWidget::ActiveSequencePlayers / StoppedSequencePlayersActiveAnimationsBlueprint/UserWidget.h:1491,1499 の UE_DEPRECATED(5.6)
UUserWidget::InitializeInputComponent()bAutomaticallyRegisterInputOnConstructionBlueprint/UserWidget.h:1713 の UE_DEPRECATED(5.7)
FWidgetStateBitfield の列挙型状態アクセサーバイナリ状態および名前付き状態のみBinding/States/WidgetStateBitfield.h:35 の UE_DEPRECATED(5.5)
UListView::InitHorizontalEntrySpacing / InitVerticalEntrySpacingSetHorizontalEntrySpacing / SetVerticalEntrySpacingComponents/ListView.h:343,346 の UE_DEPRECATED(5.6)
USlateBlueprintLibrary::TransformScalarAbsoluteToLocal / TransformVectorAbsoluteToLocalScalar_LocalToAbsolute / Vector_LocalToAbsoluteBlueprint/SlateBlueprintLibrary.h:77,87 の UE_DEPRECATED(5.6)
UGameViewportSubsystem::Get(UWorld*)UGameViewportSubsystem::Get()Blueprint/GameViewportSubsystem.h:64 の UE_DEPRECATED(5.8)
UButton::WidgetStyle / ColorAndOpacity / ClickMethod への直接的なフィールドアクセスSetStyle / SetColorAndOpacity / SetClickMethodComponents/Button.h:37,42,52 の UE_DEPRECATED(5.2)
UCommonUIActionRouterUCommonUIActionRouterBaseInput/CommonUIActionRouterBase.h:66 のクラス名
RegisterLinkedPreprocessor(Widget, Processor, int32 DesiredIndex)FInputPreprocessorRegistrationKey を受け取るオーバーロードInput/CommonUIActionRouterBase.h:87 の UE_DEPRECATED(5.5)
FUIActionBinding::TryCreate(Widget, Args)TryCreate(Widget, Args, UserIndex)Input/UIActionBinding.h:35 の UE_DEPRECATED(5.6)
FOnRerouteTouchInputDelegate、UCommonGameViewportClient::OnRerouteTouchInput()FTouchRerouteDelegate、GetRerouteTouchRegistration() / GetRerouteTouchDelegate()CommonGameViewportClient.h:15,47 の UE_DEPRECATED(5.8)
#include "Input/CommonInputMode.h"(CommonUI)#include "CommonInputModeTypes.h"(CommonInput)Input/CommonInputMode.h の UE_DEPRECATED_HEADER(5.1)
UMVVMViewModelBase::K2_BroadcastFieldValueChanged生成されたプロパティセッターMVVMViewModelBase.h:71 の UE_DEPRECATED(5.3)

よくある間違い

バインド解除せずにNativeConstructでバインドする: ウィジェットが追加されるたびにNativeConstructが再実行されるため、対応するバインド解除のないAddDynamicをそこに置くと、二重にバインドされます。NativeOnInitializedで一度だけバインドする(その時点でバインド対象のウィジェットはすでに有効です)か、NativeConstructとNativeDestructを対にして使ってください。NativeTickでは決してバインドしないでください。

メニューを閉じるためにSetVisibility(Hidden)を使う: ウィジェットはレイアウト上の領域を占めたままで、ビューポートにも(ルート化された状態で)残ります。RemoveFromParent()を呼び出すか、ツリー内に残す必要がある場合はSetVisibility(ESlateVisibility::Collapsed)を使ってください。

プレイヤー UI にCreateWidget(GetWorld(), ...)を使う: 所有するAPlayerControllerを渡してください。そうすればウィジェットにローカルプレイヤーが設定され、画面分割が機能し、GetOwningPlayer()も有効になります。

UCommonButtonBase::OnClicked()でAddDynamicを使う: これはFCommonButtonEventを返します(動的デリゲートではなく、DECLARE_EVENTです)。NativeOnActivatedでAddUObjectを使い、NativeOnDeactivatedでRemoveAll(this)を呼び出してください。

Super::NativeOnActivated/Super::NativeOnDeactivatedを省略する: Super の呼び出しはOnActivated()/OnDeactivated()をブロードキャストします。これらはウィジェットのアクティベーションツリーノード(UIActionRouterTypes.cpp:1372)がリッスンし、InputMappingをプッシュ/ポップするため、呼び出さないとフォーカス、戻る操作の処理、入力設定が機能しなくなります。

RemoveFromParent後にUPROPERTYを使わない: ウィジェットはルート解除され、ガベージコレクションの対象になります。再追加する予定がある場合は、UPROPERTY() TObjectPtr<>で保持してください。

Z オーダーを指定しない: 同じ Z オーダーで追加されたウィジェットの描画順序は未定義です。AddToViewport(ZOrder)に明示的な値を渡し、範囲を割り当ててください(例:HUD は 0~9、メニューは 10~19、ポップアップは 20 以上)。Slate はペイントパス中にウィジェットをティックするため(SWidget.cpp:1511)、HiddenまたはCollapsedの間はNativeTickが停止します。ウィジェットを表示状態に戻すためにNativeTickを頼りにしないでください。

Common UI の下でSetInputModeを呼び出す: アクティベーションツリーを迂回し、ルーターと競合します。代わりに、GetDesiredInputConfig()からFUIInputConfigを返してください。

関連スキル

  • ue-input-system — Enhanced Input、入力マッピングコンテキスト、FInputModeUIOnly/FInputModeGameAndUI/FInputModeGameOnly、入力優先度
  • ue-gameplay-framework — HUD/PlayerController がウィジェットを作成して所有する場所、画面分割時の所有権
  • ue-cpp-foundations — UPROPERTY/UFUNCTION指定子、TObjectPtr、GC ルール、サブシステム
  • ue-editor-tools — Slate の詳細なカスタマイズ、エディタユーティリティウィジェット、UToolMenus
  • ue-materials-rendering — UI マテリアル、ウィジェットから駆動されるUMaterialInstanceDynamicのパラメーター
  • ue-data-assets-tables — リスト項目やアイコンセットを支えるデータアセットとデータテーブル
  • ue-gameplay-abilities — ヘルス/リソースバーを駆動する属性変更デリゲート
  • ue-blueprint-cpp-interop — C++ を Blueprint に公開する方法:UFUNCTION/UPROPERTY のメタキー、潜在アクション、非同期ノード
  • ue-gameplay-cameras — スプリングアーム、ビュ-ターゲット、カメラモディファイア、シェイク、Gameplay Camera System

コメント