Widgetの取り扱いについて気になることがあったので、ちょっと調べてみました。
まず、Widgetを画面に表示するには、いつものコンビネーション。
Create Widget ノードと Add to Viewport ノードです。
大抵のサンプルはこの辺でめでたしめでたしなんですが・・・
まず
消すにはどうするのか?
これは公式にも載ってますが、Remove from Parentノードを使います。
これで、画面(Viewport)からは消えます。でもメモリからは消えていないので再びAdd to Viewportすることができます。
いなくなったわけではないのね
上の図でも分るとおり、Create Widgetの戻り値(ReturnValue)を変数にしてるので当たり前だとお叱りを受けそうですが、画面から消えている状態(描画されない)でWidgetが持っている関数や変数にはアクセスできます。見えていないのにアクセスは受け付けてしまうところは、安全のためにキッチリと対策しておく方がよさそうです。
Tickはどうなっているのか、ということでPrintStringノードをつないで確認してみたら、Remove from Parentした時点で停止します。アニメーションを再生していても停止します。
Event Destruct って
Remove from Parentすると、Widget専用のイベント Event Destruct が走ります。
Widget作成時に置かれていないので隠れているのを引っ張り出す必要がありますが、ここにイベントディスパッチャーをCallするようにつなぐと、結構便利そうです。ただ、Remove from Parent した時点でViewportから即座に消えてしまうので、フレームアウトやフェードアウトの演出をさせても無駄になります。
出したり消したり
ポーズメニューのように常駐させて利用するような場合は、Add to Viewport と、Remove from Parent のコンビネーションで、出したりひっこめたりできて大変便利です。
表示するたびに CreateWidget する必要はありません。
CreateWidgetのタイミングにご注意
Remove from Parent で消えている状態で、CreateWidgetするのは問題ないです。中の変数は初期化されます。
危険なのは、Viewportに乗っている状態(消えていない状態)でCreateWidgetすること。CreateWidgetするたびに新しく生成されてしまいます。そして古い方は触れなくなるので画面に残り続けることになります。
何度も表示・非表示を繰り返す場合は変数化しておいて、上の2つのノードを使うのがベストだと思います。
Event Construct について
Widgetには、EventConstruct というイベントが最初から利用できます。
普通のブループリントに用意されている Event Begin Play と同じような扱いで Add to Viewport されたタイミングで1度だけ走ります。Widget には Construction Script が用意されていません。なので、変数の初期化とか諸々のセットアップはここで行うことが多くなると思います。
Widget を 出したり引っ込めたりするたびに、Add to Viewport ノードによってEvent Construct が処理されてしまうのを防ぐために、DoOnceノードを使うといい感じです。
ブール値の変数をフラグとして使って判定する方法もアリだと思いますが、DoOnceノードだと変数を増やさなくていのでオススメ。
完全に消したいときは?
メモリ節約?のために用が済んだWidgetを葬りたいときはどうするか。
まずCreate Widgetの戻り値を変数化(右クリックしてPromote to Variable)しておくことが前提です。
そして、Remove from Parent した後に、変数を空にします。
こうしておけば、中の関数やら変数にアクセスできなくなります。
アクセスするとエラーが出ます。
ちなみに、Viewport に存在している状態で、さらに Add to Viewport するとWarning がログに吐き出されます。
Widgetの取り扱いについて気になったとこを検証してメモしました。
プログラマ的な検証ではないのでいろいろ間違ってるかもしれません。
ご指摘いただけると嬉しいです。
ではみなさん楽しいUMGライフを!