SObjectPropertyEntryBoxでActorアセットを選択する話

Unreal Engine 4 (UE4) その2 Advent Calendar 2020 4日目の記事です。

SObjectPropertyEntryBoxでAllowedClassにActorを入れると、Levelに存在するActorの中から選ばされるから、ActorのBlueprintアセットを選択するようにするちょいテクニックの話。

はじめに

Editor Utility Widgetしてますか?
良いっすよねEUW。
Slateはまぁ分かるっちゃ分かるような気がするけど、黒魔術感が半端ない。Slotを呼び出してしつつ、[]入れ子にする。まぁ分かるよ。C++にしては直感的だけどさ....
それに比べてEUWはUMGとBlueprintで書けちゃう。惚れてまうやろ。

とはいえ、パーツ数はそんなに多くない。まぁそうだよね。Slateにあるんだから。
SlateにあるものはUMGでも使えます。でもそのままじゃ使えないので、NativeWidgetHostというもので、UMGへ公開してあげる必要があります。
NativeWidgetHostは、単一のSlateや自分で組んだSlate群をUMGに昇格(上も下もないが...)するクラスです。
詳しい実例は、あまりにも有名な以下のページへ。

unwitherer.blogspot.com

SObjectPropertyEntryBoxを使う

EUWで欲しいパーツの1つでもあるSObjectPropertyEntryBox。
よく見るやつです。BP_Sky_Sphereとかでも光源を選ぶ時に使うやつ。

f:id:crssnky:20201025222200p:plain

実はこれ、許可するクラスを選択する時にActor以外を選ぶと、アセットを選ぶことができます。こちらはTextureクラスを指定した様子。 f:id:crssnky:20201107221334p:plain

SObjectPropertyEntryBoxの元となったPrivateなSlate、SPropertyEditorAssetの308行目にそれっぽい判定はあります。

bIsActor = ObjectClass->IsChildOf(AActor::StaticClass());

Actor継承系を指定するとActor選択用のUIになり、それ以外だとアセット選択用のUIになるわけです。(上のIsChildOf判定の後にそれぞれのSlateを仕込む文がある)

Actorアセットを選択したい

EUWをやっていると、ActorのBlueprintアセットを自動編集させたいことがあると思います。しかし、単純にSObjectPropertyEntryBoxのAllowedClassにActorを入れてしまうと、Level内から選ばされてしまいます。

SAssignNew(m_entryBox, SObjectPropertyEntryBox)
    .AllowedClass(targetClass) // UClass* targetClassとしてBlueprintからActorを入れてあげる
    .OnShouldFilterAsset_Lambda([this](const FAssetData& assetData){return false;});

f:id:crssnky:20201108160529p:plain でも本当に欲しいのは、こっちです。 f:id:crssnky:20201110231454p:plain

え?SClassPropertyEntryBoxを使えって?
サムネイルがあった方が便利じゃないです?
(ツリー状態で見たい場合はSClassPropertyEntryBoxを使いましょう)

SObjectPropertyEntryBoxの設定を頑張る

主に使用する設定は以下の通り

  • AllowedClass
    • 許可するクラスをUClass*で指定する
  • OnShouldFilterAsset_Lambda
    • AllowedClassに加え、見つかった個々のアセットに対してさらにフィルターするか判別する関数

これらを使用して、UNativeWidgetHostするならばこうなります。

  • 05行目:許可したいクラスがBlueprintかどうかを調べる
  • 09行目:許可したいクラスがBlueprintだった場合はUBlueprintを、そうでない場合は入力した許可したいクラスをAllowedClassとする
  • 10行目:フィルター関数を定義する
  • 12行目:許可したいクラスがBlueprintかどうかで場合分け
    • 26行目:Blueprintじゃない場合は何もフィルターしない(falseを返す)。
  • 15行目:Blueprintのアセットのはずだけど、一応nullptrチェック
  • 17行目:検査対象のBlueprintのParentClass(Blueprintが持つクラス)が、許可するクラスを継承しているかどうか
    • trueだとフィルターする(画面に表示しない)ので、IsChildOf()の結果を反転する

こうすることで本当に欲しかった、targetClassにActorを選んでもそのActorを継承したクラスを持つBlueprintアセットを選択することができるウィジェットを実現することができます。

UNativeWidgetHostを継承したクラス全体も公開します。
みなさんも、良いEditorUtilityWidgetライフを!

今すぐ使えるソース全体はこちら↓
crssnky/UBlueprintSelectBox.cpp