UE5 Common UI お試し ① ボタンのアイコンを出し分ける - You are done!
上記の続きです。
前回は公式のクイックスタートをなぞる形でした。今回は機能別サンプルをもう少し眺めていきたいと思います。
コード
Release blog20221026 · dany1468/UE_CommonUISample · GitHub
blog20221026
でタグを打ってあります。
CommonButtonBase の InputActionWidget
前回ボタンの parent に指定した CommonButtonBase
ですが、非常に多くの機能があるようです。その中に InputActionWidget
というプロパティが存在します。
/** * Optionally bound widget for visualization behavior of an input action; * NOTE: If specified, will visualize according to the following algorithm: * If TriggeringInputAction is specified, visualize it else: * If TriggeredInputAction is specified, visualize it else: * Visualize the default click action while hovered */ UPROPERTY(BlueprintReadOnly, Category = Input, meta = (BindWidget, OptionalWidget = true, AllowPrivateAccess = true)) UCommonActionWidget* InputActionWidget;
前回の記事では以下のようにボタンの BP を記述しました。
一方で機能別サンプルの方では以下のように一見すると設定が足りないような内容になっています。(ボタンを構成する Widget 群は同じなのに関わらずです)
これには理由があり、機能別サンプルの方はボタンに配置している CommonActionWidget
を InputActionWidget
という名前に変更し、CommonBaseButton
の InputActionWidget
に設定する形にしているのです。そのためか、機能別サンプルの方ではグラフの方に CommonActionWidget
の Variables が表示されません。
継承されている変数の方に入っています。
そして、この変数名 (InputActionWidget
) に合わせることで以下の処理が実行されます。
void UCommonButtonBase::UpdateInputActionWidget() { // Update the input action state of the input action widget contextually based on the current state of the button if (GetGameInstance() && InputActionWidget) { // Prefer visualizing the triggering input action before all else if (!TriggeringInputAction.IsNull()) { InputActionWidget->SetInputAction(TriggeringInputAction); } // Fallback to visualizing the triggered input action, if it's available else if (!TriggeredInputAction.IsNull()) { InputActionWidget->SetInputAction(TriggeredInputAction); } // 以下略 } }
つまり、CommonButtonBase
側に設定された TriggeringInputAction
が InputActionWidget
にも設定されているということです。
前回のノードを見てもらうと分かる通り、SetInputAction
を BP 側で設定する処理が C++ 側で行われていることが分かります。この UpdateActionWidget
は Activate
時にも呼ばれるため、機能別サンプルのノードはあれだけで問題なく動作するということです。
自分のサンプルの方も変更
外部からボタンの文字列 (Text
) を指定しているかどうかで分岐するようにしています。(TriggeringInputAction
を指定しない場合にText
を指定するという感じで)
加えて、InputActionWidget
に設定を入れる UpdateInputActionWidget
関数が Pre Construct
では呼び出されないので、Construct
に変更しています。
デフォルトナビゲーション
デフォルトナビゲーションに関しては 3. デフォルトのナビゲーション アクションの設定 | Unreal Engine の共通 UI クイックスタート ガイド | Unreal Engine ドキュメント を前回スキップしました。
ただ、設定することは関してはクイックスタートの通りです。
ただ、今回はお試しでもあるので、Default Click Action
に関しては、異なるキーを割り当てることにしました。
追加した TestGlobalForward
、キーボードの P
と、ゲームパッドの L
を割り当て。
NavigationInputDataExample
の Default Click Action
にそちらを割り当て。
これらの設定は以下の UCommonUIInputData
のコードが対応します。
/* Derive from this class to store the Input data. It is referenced in the Common Input Settings, found in the project settings UI. */ UCLASS(Abstract, Blueprintable, ClassGroup = Input, meta = (Category = "Common Input")) class COMMONINPUT_API UCommonUIInputData : public UObject { GENERATED_BODY() public: virtual bool NeedsLoadForServer() const override; public: UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (RowType = CommonInputActionDataBase)) FDataTableRowHandle DefaultClickAction; UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (RowType = CommonInputActionDataBase)) FDataTableRowHandle DefaultBackAction; };
また、これらを取得するコードは UCommonInputSettings
にあります。
UCLASS(config = Game, defaultconfig) class COMMONINPUT_API UCommonInputSettings : public UDeveloperSettings { FDataTableRowHandle GetDefaultClickAction() const; FDataTableRowHandle GetDefaultBackAction() const;
Default Click Action の利用箇所
上記の GetDefaultClickAction
を調べると、先程の UCommonButtonBase::UpdateInputActionWidget
のみが該当しました。
void UCommonButtonBase::UpdateInputActionWidget() { // Update the input action state of the input action widget contextually based on the current state of the button if (GetGameInstance() && InputActionWidget) { // Prefer visualizing the triggering input action before all else if (!TriggeringInputAction.IsNull()) { InputActionWidget->SetInputAction(TriggeringInputAction); } // Fallback to visualizing the triggered input action, if it's available else if (!TriggeredInputAction.IsNull()) { InputActionWidget->SetInputAction(TriggeredInputAction); } // Visualize the default click action when neither input action is bound and when the widget is hovered else if (bShouldUseFallbackDefaultInputAction) { FDataTableRowHandle HoverStateHandle; if (IsHovered()) { // 💡 ここが該当箇所 HoverStateHandle = ICommonInputModule::GetSettings().GetDefaultClickAction(); } InputActionWidget->SetInputAction(HoverStateHandle); } else { FDataTableRowHandle EmptyStateHandle; InputActionWidget->SetInputAction(EmptyStateHandle); } UpdateInputActionWidgetVisibility(); } }
これは CommonButtonBase
になるのですが、TriggeringInputAction
が Null であり、かつ bShouldUseFallbackDefaultInputAction
が True であることがまず前提条件になるようです。
前回の記事では Triggering Input Action
に指定することでボタンのアイコン表示や入力への反応を設定しましたが、あえて未指定にします。 Should Use Fallback Default Input Action
は前回も true にしていました。
つまり、対応する Input Action が存在せず、Fallback が有効になっている時に代わりに Input Action として設定されるのが Default Click Action
ということになりそうです。
加えて IsHovered
が条件になっているので分かる通り、ホバーされている場合のみ表示されます。
UI を作る
前回の WBP_Menu
の右端に Default Click Action
用のボタンを足します。
先程も Input 部分は説明しましたが、Default Click Action
用のボタンの設定は以下のようにします。
ホバー無し | ホバー時 | |
---|---|---|
Keyboard |
||
Gamepad |
入力には反応しない
ホバー時の表示としてはアイコンが表示されるのですが、P
や Gamepad の L
を押してもクリックイベントは反応しません。
機能別サンプルでこれが使われている箇所を見ても、おそらく特別なキーを割り当てたりはせず、Mouse & keyboard
ではマウス、Gamepad
ではデフォルトの確定&Confirm キーを指定するのだと思います。
以下は Construct から呼び出される関数になるのですが、TriggeringInputAction
が UCommonButtonBase
に指定されていない場合には UCommonButtonBase::HandleButtonClicked
が紐付けられないため、入力に反応できません。
void UCommonButtonBase::BindTriggeringInputActionToClick() { if (TriggeringInputAction.IsNull() || !TriggeredInputAction.IsNull()) { return; } if (!TriggeringBindingHandle.IsValid()) { // 💡ここでイベントを紐づけないとクリックをハンドルできない FBindUIActionArgs BindArgs(TriggeringInputAction, false, FSimpleDelegate::CreateUObject(this, &UCommonButtonBase::HandleButtonClicked)); BindArgs.OnHoldActionProgressed.BindUObject(this, &UCommonButtonBase::NativeOnActionProgress); BindArgs.bIsPersistent = bIsPersistentBinding; BindArgs.InputMode = InputModeOverride; TriggeringBindingHandle = RegisterUIActionBinding(BindArgs); } }
まとめ
Default Back Action
までまとめてやりたかったんですが、Default Click Action
の入力が反応しないことに引っかかって時間がかかってしまいここで一旦打ち切りになりました 😅
Default Click Action
に関しては、クイックスタート通りに、Keyboard の場合は無し、Gamepad の場合は Gamepad Face Button Bottom
を指定しておくのが無難なのではないかと思います。(Switch 等は別だと思いますが)