2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unreal Engine (UE)Advent Calendar 2024

Day 6

EditorUtility で生成した Widget のプロパティを設定する

Last updated at Posted at 2024-12-05

こんにちは、葉乃音 (HANON) と申します。

普段は Shiden という Unreal Engine 5 用ノベルゲームエディタプラグインの開発をしています。(現在ベータ版を GitHub で公開中です。)

今回はこのプラグインを作る過程で直面した小ネタを。

悩んだこと

Shiden にはインゲームやエディタ上で使用するアセットをテンプレートから複製する機能があります。

たとえばセーブ画面を自作したい時、こんな感じに選択をすると...

こんな感じで必要なアセットがテンプレートから複製されます。
image.png

本プラグインにおけるセーブ画面はメインの SaveMenu クラスと各セーブスロットの SaveSlot クラスの2つからなります。

image.png

そして、これらには SaveMenu クラスから SaveSlot クラスへの依存関係が存在します

image.png

さて、テンプレートから各々のアセットを複製するだけでは、これらの依存関係までは設定されないので、どうにか設定してあげる必要があります。

ですが、どうやったら生成したばかりの Widget の設定を変更できるのでしょうか? もちろんユーザに手動で設定してもらうのもナシではないですが、出来れば避けたい...。

ここで小一時間悩むことになりました...。

下準備

とりあえず参照関係の自動設定を実現するために、出来ることをやっていきましょう。

まず SaveMenu のテンプレート (これは単なる Widget の Blueprint です) を開き、 SaveSlot クラスを参照できるよう、任意の User Widget クラスを指定できる変数 SaveSlotClass を用意しました。

つまり SaveMenu のテンプレートを複製した際 (以降、複製したものを MySaveMenu クラスとします)、この SaveSlotClass 変数に同時生成した SaveSlot クラス (以降、MySaveSlot クラスとします) を自動設定するのがゴールになります。

image.png

テンプレートから複製する処理と参照関係を自動設定する処理は EditorUtilityBlueprint に書いていきます。

テンプレートからの複製は Duplicate Asset ノードを使って簡単に行えます。ここで注意したいのは、複製したオブジェクトそのものはあくまで BlueprintWidget であることです1

今回やりたいのは UBlueprintWidget オブジェクトのプロパティの値変更ではなく、MySaveMenu クラスの SaveSlotClass 変数のデフォルト値を変更すること。そのため、Load Blueprint Class ノードの引数に複製したオブジェクトのパスを指定して、Blueprint に紐づいている MySaveMenu クラスを取ってくる必要があります。

image.png

あとは取得した MySaveMenu クラスのデフォルト値を変更するだけです。しかしここからが厄介です。なぜなら、Blueprint ではクラスのデフォルト値を変更することはできないからです。

こんな感じの Get Class Defaults というデフォルト値を取得するノードはありますが、デフォルト値を変更するノードは Blueprint にはありません。

image.png

したがって、ここからはコードの出番です。

解決策1: C++ を使用する

C++ を使用する場合はこんな感じのコードを書くことで実現できます。

TargetClass から DefaultObject を取得し、SetObjectPropertyValue() によって PropertyName 変数の値を変更しています。

void SetClassProperty(const UClass* TargetClass, const FName PropertyName, UClass* PropertyValue)
{
	FProperty* Prop = TargetClass->FindPropertyByName(PropertyName);
	const FClassProperty* ClassProperty = CastField<FClassProperty>(Prop);
	void* ValuePtr = ClassProperty->ContainerPtrToValuePtr<void>(TargetClass->GetDefaultObject());
	ClassProperty->SetObjectPropertyValue(ValuePtr, Value);
}

EditorUtility のほうはこんな感じ。CreateAsset ノードは自作ですが、やっていることは既存ファイルとファイル名を被らないようにしつつテンプレートから複製しているだけです。

image.png

解決策2: Python を使用する

Execute Python Script ノードを使用するのも一つの手です。
C++ のコードを書かなくて済むのでサクッと済ませたい場合はこちらが良いでしょう。

UE5 には Python Editor Script Plugin というプラグインがデフォルトで入っており、これを有効にすることで python を使用できます。

image.png

EditorUtility はこんな感じになります。Execute Python Script ノードは Detail から引数を設定することができます。

image.png

スクリプトの中身はこんな感じです。

import unreal

bp_save_menu_default_object = unreal.get_default_object(save_menu_class)
bp_save_menu_default_object.set_editor_property("SaveSlotClass", save_slot_class)

やっていることは SaveMenu クラスの default object を取得して、set_editor_property() で SaveSlot クラスをセットしているだけです。

まとめ

Unreal Engine 5 のエディタ拡張は機能が豊富かつ優秀ですし、Blueprint だけでも大体どうにかなりますが、それだけで実現できない個所は、今回みたく C++ や python も積極的に使っていきたいですね!

明日は @T_Sumisaki さん、@tukigaselio さん、@Szr_Asakura さん、@uxtuno_ さんです!
どんな記事になるのか楽しみです!

  1. ちょっとややこしいのですが、エディタ上で目にする Widget のアセットは UWidgetBlueprint が特定の UUserWidget 継承クラスと関連づいた形で出来ています。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?