スレートとは「直接モード」の UI フレームワークです。つまり、フレームごとに UI 全体を作りかえます。これは、グラフィックスとアニメーションが豊富な非常に動的なインターフェイスに最適ですが、UI で何も変更する必要がない場合は、不要なプロセッサを使用することになります。アクティブ タイマー システムにより UI の更新が不要な場合にスレートをスリープ態にすることができます。アクティブ タイマー機能は、エディタ UI での作業中に使用しますが、リアルアイム ビューポートのあるゲームの場合は UI での作業でも使用しません。
スレートは、以下の両方が所定のフレームに対して true の場合、スリープになります。
- ユーザー アクションがない
- アクティブ タイマーを実行する必要がない
ユーザー アクションとは、マウスの移動、クリック、キーの押下を指します。
下図は、スレート アプリケーションがフレームごとにティックする様子を表したものです。

この図は、エディタのプロセッサの処理時間の推移を表したものです。

アクティブ タイマー
アクティブ タイマーはウィジェットに明示的に登録されたデリゲート機能で、ユーザー アクション (タイマーの「アクティブな」性質) がない場合でも、実行時にスレート ティック / ペイント パスを引き起こします。 アクティブ タイマーは、登録が削除されるまで、実行期間によって定義された頻度で無限に実行し続けます。
オリジナルの Tick()
関数は「passive」ティックとして存在しています。これまでのようにスレートに呼び出されますが、スレートが起きている場合のみです。今後 PassiveTick()
と名称変更する可能性がありますので、
Tick()
は非推奨です。
アクティブ タイマーの登録は以下の手順で行います。
- 以下のシグネチャを使って関数を定義します。
EActiveTimerReturnType Foo(double InCurrentTime, float InDeltaTime)
- それを
FWidgetActiveTimerDelegate
にバインドします。 - デリゲートと
SWidget::RegisterActiveTimer()
へのタイマー実行 (フレームごとの呼び出しは 0) の勘間隔をパスします。
アクティブ タイマーの登録削除は、以下の 3 通りの方法で行います。
EActiveTimerReturnType::Stop
をデリゲートから戻すSWidget::RegisterActiveTimer()
から戻されたFActiveTimerHandle
とSWidget::UnRegisterActiveTick()
へパスする- アクティブ タイマーが登録されているウィジェットを廃止する
現時点ではアクティブ タイマーは全部かゼロかの状況なので、単一のアクティブ タイマーを実行するとスレートのすべてがティックされます。さらに、 ウィジェットが同時登録可能なアクティブ タイマー数に制限はありません。非常に便利な機能ですが、複製登録が発生する可能性があります。それを防ぐために、 以下のいずれかの方法で登録ステータスをトラックします。
-
アクティブ タイマーが登録されているかどうかをトラックするためにウィジェットでフラグを維持する
- UE4 コードベースで例えば
bIsActiveTimerRegistered
を検索する
- UE4 コードベースで例えば
-
RegisterActiveTimer()
から戻されたFActiveTimerHandle
に弱いポインタを格納し、無効な場合のみ登録する- UE4 コードベースで例えば
TWeakPtr<FActiveTimerHandle> ActiveTimerHandle
を検索する - メモリ節約のために、アクティブ タイマーの登録削除がどうしても必要な場合のみ、このメソッドを使用してください。
- UE4 コードベースで例えば
一般的なユースケース
以下の一般的なユースケースに対して、お勧めのアクティブ タイマーのセットアップ方法を説明します。
-
アクションをトリガーする場合
EActiveTimerReturnType::Stop
を常に戻す間隔を 0 にしてアクティブ タイマーを登録します。
-
FCurveSequence で制御されないアニメーションや補間を行う場合
- 慣性スクロールが開始されると、間隔が 0 であるアクティブ タイマーを登録することによって、毎フレーム スクロースを更新できるようにします。
- 目的に到達するまで、
EActiveTimerReturnType::Continue
を戻し続けます。 - ターゲットの目的に到達したら、
EActiveTimerReturnType::Stop
を戻して登録削除をします。
例となるのが、慣例のスクロールです。
SScrollBox
を参照してください。 -
別のサブメニューを開いたり、タブをドッキングさせたりして、遅延後にアクションを取る場合
- ゼロではない正の値の遅延で登録します。
アクティブ タイマーの時間間隔は一回登録すると変更はできません。実行前に遅延をリセットするには、アクティブ タイマーを明示的に登録削除して、再登録しなければなりません。
-
アクションを定期的かつ無制限に実行する場合
- ゼロではない正の間隔で登録して、
EActiveTimerReturnType::Continue
を返し続けます。
- ゼロではない正の間隔で登録して、
FCurveSequence およびアクティブ タイマー
FCurveSequence
の API がアップデートされ、ウィジェットのアニメート中のアクティブ ティックの登録処理が簡素化されました。
シーケンスのプレイには、アニメート元であるウィジェットへの参照が必要になりました。
シーケンスの再生中、パスされたウィジェットの代わりに空のアクティブ ティックが自動的に登録されます。
シーケンスを再生すると、シーケンスのループが指定されるようになりました。ただし、これによりアクティブ ティックが無制限に登録されるので、注意して使用してください。
ループの有無に関わらず、アクティブ ティックは Pause()
、JumpToStart()
、JumpToEnd()
を呼び出すと登録削除されます。
スレート スリープのテスティング
スレートのスリープ機能には、関連するコンソール変数が 2 つあります。
Slate.AllowSlateToSleep
は、スレートをスリープ ステートにできるかどうかを調整します。この変数はデフォルトで有効になっています。Slate.SleepBufferPostInput
は、スレートを起きている状態を維持させる最後のユーザー アクション後の時間を指定します。デフォルトは 0 です。スリープ システムの恒久機能ではないので、デバッグ処理のみに使用します。
目標としているスリープ状態が可能なスレートは、絶対にスリープ状態にならないスレートとは区別ができないため、スレートがスリープ状態なのか判断は難しいです。現在、これをモニターする最善の方法は、 エディタ フレームレート ([Editor Settings]->[Miscellaneous]->[Show Frame Rate and Memory]) を表示することです。フリーズすると、スレートはスリープになります。