
データ ドリブン型 UI について
データ ドリブン型 UI エレメントは、基本となるデータソースに基づいてプロシージャルに構築されています。この形式の素晴らしい点は、UI によって公開されているシステムに対し、デザイナーが UI そのものに何の調整もせずに変更できることです。一方、最大の欠点は、エレメントがランタイム時のみしか存在しないため、プレビューができず、ゲームでの最終的な見え方が調整しずらいことです。例えば、ゲームのショップについて考えてみましょう。インターフェースではすべての購入対象品リストに料金とアイコンを付けて表示しなければなりません。すべての情報を載せてウィンドウをビルドすることはさほど難しくないのですが、デザイナーがショップにあるアイテムの追加 / 削除を行う場合や、料金の変更やアイコン アートの更新が必要な場合はいささか問題です。なぜなら、このような作業にはインターフェースの変更が伴うからです。これを忘れるとインターフェースがデータと同期していない状態になります。ゲームでリストに 500 ゴールドで載っていたアイテムを購入したら自分のインベントリから 1000 ゴールド引かれてしまっていたらショックですよね。
このブログでは、データ テーブルの設定およびスクロール リストに任意の数だけアイテムを表示するショップ ウィジェットへの連携方法を説明します。さらに、選択された時のイベントの配信方法を紹介し、皆さんのプロジェクトのニーズを満たすようにこれらのアイデアを拡張する方法について説明したいと思います。
まず最初に
データ ドリブン型 UI エレメントで最も重要なのはデータそのものです。それではショップのインベントリを入れるデータ テーブルを設定しましょう。最初に、テーブルの各行に入れるカラムを表す構造体を作成しなければなりません。[Add New] をクリックし、ブループリント カテゴリを開いて、Structure をクリックして構造体を作成します。
このように設定してみました。
このように設定してみました。

データ テーブルは後ほど自動追加されるので、名前の入力欄を作っていないことに注目してください。テーブルで特定のエントリを参照する必要がある場合のみ名前を使います。
次に、データ テーブルそのものを作成します。[Add New] を再度クリックして [Miscellaneous] カテゴリを展開します。さきほど作成した構造体を選択して、エントリをいくつか追加してみましょう!
次に、データ テーブルそのものを作成します。[Add New] を再度クリックして [Miscellaneous] カテゴリを展開します。さきほど作成した構造体を選択して、エントリをいくつか追加してみましょう!

データが入力されたので、ウィジェットを 2 つ作成していきます。まずはメインとなるショップ ウィンドウです。ショップが利用できる場合はいつでも作成します。次に ItemRow ウィジェットを作ります。データ テーブルの行を表すためにランタイム時に作成されます。
ItemRow から作成してみよう目標は、様々なテキストの長さに合うように調節可能なレイアウトで、自動複製および追加が可能な汎用ウィジェットの作成です。
最大のテキストサイズとアイコンサイズを想定してウィジェットを作成してみました。
ItemRow から作成してみよう目標は、様々なテキストの長さに合うように調節可能なレイアウトで、自動複製および追加が可能な汎用ウィジェットの作成です。
最大のテキストサイズとアイコンサイズを想定してウィジェットを作成してみました。

開始キャンバス パネルを階層のトップから削除されているのが分かります。
さらに、データをテンプレートに追加する SetValues 関数も作成しました。便利で簡単なソリューショーンのためにプロパティ ビルドを使うこともできましたが、バインドはティックごとに値を更新します。パフォーマンスが重要な場合は、バインドを避けて、必要な場合のみプロパティを更新するイベントを設定します。
さらに、データをテンプレートに追加する SetValues 関数も作成しました。便利で簡単なソリューショーンのためにプロパティ ビルドを使うこともできましたが、バインドはティックごとに値を更新します。パフォーマンスが重要な場合は、バインドを避けて、必要な場合のみプロパティを更新するイベントを設定します。

次に、エントリを入れるメイン ウィジェットを作成します。このウィジェットには、データ テーブルでの読み込みと各行に ItemRow ウィジェットを作成するブループリントが含まれます。一時的に ItemRow ウィジェットを置いて可視化することもできますが、ブループリントによって行が追加されるので、完成品に空のスクロール ボックスを作りました。


ここでメイン ウィジェットにビューポートを追加すると、データベースから最新情報がすべて入力されます。データテーブルを更新するだけで、エントリーを追加、削除、変更が行えます。

改善点
実際に PIE を開始してショップ インスタンスを表示させなければなりません。試行錯誤して調整を行うことに困惑すると思います。4.15 以降のエンジンを使用していればラッキーです。ウィジェット ブループリントに Event Pre Construct ノードが追加されているからです。編集時に起動するためプレイせずにプレビュー ビューポートでウィジェットがどのようにみえるのか確認できる点を除けば、基本的には Construct ノードと同じです。行のビルドに使っていたブループリントを Construct ノードから外して、 Event Pre Construct ノードにアタッチします。データ テーブルを変更した場合は、ボタンにいつも通りのチェックマークが付いている場合でも、Compile を使ってプレビュー ウィジェットを再ビルドする必要があるので注意してください。
もう 1 つ重要なことがあります。それは、Event Pre Construct に接続されているノードがいつも通りにランタイム時に呼び出されても、それらの呼び出しはプレビュー エディット上のブループリント エディタ内で行われています。表示上のコードだけを使うようにして、ランタイムまで存在しないものへの参照は避けてください。

任意のアイテム リストが表示中であっても、ゴールドを差し引いてアイテムをプレイヤーのアイテム欄に追加するボタンがクリックされた時、他のゲーム システムに情報を伝える手段 (キャラクター コントローラーなど) が必要なことにも留意してください。個々のエントリと特定のボタンが押された時にイベントを受け取りたい人の中間的な役割を担うイベント ディスパッチャーをトップ レベル ウィジェットに作成して、できるだけモジュラー形式を保ちます。ItemRow は、ItemRow の OnMouseButtonDown に上書きすると呼び出されるイベントを発行することができるように、ルート ウィジェットに戻るハンドルが必要です。

ItemRow ウィジェット
関係者は、カスタム イベントをルート ウィジェットのイベント ディスパッチャーにバインドし、クリックされたアイテム名をパラメータとして受け取り、詳細はデータ テーブルを独自に参照することができます。

メインのトップ レベル ウィジェット
この例で使ったデータ テーブルは編集時のみの変更を意図していることも理解しておいてください。ゲームの進行途中で変更ができるようなダイナミック データ構造が必要なケースもあります。データ テーブルをデータの開始ステートとして使用しても、必要に応じてそれを他の構造体にコピーして変更することができます。汎用性を最大にするために、UI にこれらのプロパティの表示方法を指示する任意のプロパティとメタデータを使ってデータ構造体を作成することができます。思わぬ制限事項に引っかかって慌てるよりも、自分に適したソリューションを予め考えておいた方が賢明です。