ゲーム作りが大好きな人のブログ

ゲームを作るのが大好きな人のブログ。UE4とBlender、MAYA(LT)、3DCoatを使用しています!

【UE】【C++】【UMG】C++からUMGのウィジェットやアニメーションを取得する

Unreal Engine (UE) Advent Calendar 2022 その3」1日目の記事となります。

はじめに

自作ゲームの方で長くUMGを触ってきましたが、理解度が深まって来たので情報を共有します。今回はC++からUMGのウィジェットやアニメーションを取得する方法について解説です。

※検証バージョン UE4.27.2(Developmentパッケージでも動作確認)
※将来的にUE5でも検証予定で差異があれば追記します
※間違えてたらコメント欄で教えていただけると嬉しいです

 
 

ウィジェットの取得

下記のようにUPROPERTYを定義します。すると変数名と同名ウィジェットがバインドされます。

UPROPERTY(meta = (BindWidget))
UMyTextBlock*           WidgetName = nullptr;

 

問題点

しかし上記の方法はUserWidget内に変数名と同じウィジェットが存在しないとブループリントコンパイルエラーとなります。

これを防ぐには

UPROPERTY(Transient, meta = (BindWidgetOptional))
UMyTextBlock*           WidgetName = nullptr;

BindWidgetOptionalに変えます。

これでエラーを回避できます(ただし、↑のようなアドバイス的な文章は残る)。
 
 

アニメーションの取得

UPROPERTY(Transient, meta = (BindWidgetAnim))
UWidgetAnimation*           AnimationName = nullptr;

使い方はBindWidgetと似ています。変数名と同名のアニメーションを取得します。また、Animationの場合はTransientを付けないとエラーが出ます。こちらもOptional版があります。
 
 

基本は~~Optionalを使うのを推奨?

処理としては共通だけど片方のウィジェットには文字を表示したいが、もう片方には表示させたくない等はよくある話かと思います。

この場合、片方のUMGには該当のテキストウィジェットを削除しますが、Optionalではない場合BPコンパイルエラーとなってしまいます。

上記のようなエラーを避けるためにもOptionalで実装する方がよいかと思われます。
 
 

UPROPERTYを使用しないでWidgetを取得する方法

実はUPROPERTYを使用せずともWidgetは取得できます。自分はもっぱらこっちのやり方をやっていたり。

void UTestUserWidget::NativeConstruct()
{
	UTextBlock* _txtTitle = Cast<UTextBlock>(GetWidgetFromName(TEXT("txtTitle")));
	Super::NativeConstruct();
}

このやり方はNativeConstructの負荷が少し上がりますが、UPROPERTYを使わないといった利点もあります。

あとSuper::NativeConstruct()の前にやるのを推奨です。後にやってしまうとBP側のEventConstructが先に走るので、その際に変数を参照するような作りにするとnullptrアクセスしてしまいます。
 
 

まとめ

  • BindWidget~~を使うと自動でバインドしてくれる
  • GetWidgetFromNameを使うと名前からウィジェットを取得してくれる

という感じです。今回はこんな所で。
 
 

おまけ:ウィジェットの取得(BindWidgetOptional)にTransientを付与してみたら

参考文献ではウィジェット取得時のUPROPERTYにTransientが付いてないのですがTransientを付けていてもパッケージで動作するようです

調べてみましたがUserWidgetを生成時(UUserWidget::Initialize内部)にウィジェットと同名のプロパティ検索をかけ、そこでプロパティとバインドしているのでTransientが付いていても問題ないようです。

でも、そこで検索かけると負荷がかかるのでは?と思いました。この辺りはどれが正解なのかピンと来ていませんが一例として残しておきます。