読者です 読者をやめる 読者になる 読者になる

みつまめ杏仁

アンリアルエンジン(UE4)でGUIを作るためにゴニョゴニョしてます。UIデザイナーの皆様の助けになれば幸いです。

テキストブロックのスクロール

f:id:hiyokosabrey:20170218200852p:plain

 テキストブロックで、長文を表示しようとしたときに、たいていAuto Wrap Text(=自動改行)にすると思います。

f:id:hiyokosabrey:20170218203113p:plain

文字量が多いとサイズが大きくて表示しきれないので、スクロールさせるのが我々UI業界では当たり前の仕組みです。

 

UMG パーツ

f:id:hiyokosabrey:20170218220855p:plain

 まずはイイ感じの大きさのキャンバスパネルを置いて、その子供にテキストブロックとイメージを配置します。キャンバスは表示範囲を限定するためのものです。子供たちにとってこのキャンバスパネルが実際に表示される大きさになるので、アンカーの設定を右下のやつに設定します。

f:id:hiyokosabrey:20170218221511p:plain

スロットの設定は以下のようにすると、親のキャンバスパネルにピッタリフィットするように可変します。

f:id:hiyokosabrey:20170218221818p:plain

 Offset ~ は余白が欲しい時に設定します。

 

Event Construct

事前に取得できて後から再利用できる値は、なるべく変数化しておきます。

f:id:hiyokosabrey:20170219223957p:plain

 ここでは、見える範囲と一度にスクロールする量を求めて変数にしています。

 

 テキストブロックの中身を変える

 UMGのテキストブロックには、内容を変更する方法が3つ(他にもあるかも)用意されています。

1.テキスト型の変数に直接バインドしてしまう方法Flashみたいな)

  その変数の内容を書き換えるだけで反映されます

2.関数にバインド(紐づけ)して、その関数の戻り値を使う方法

  その関数にパラメータ(引数)を渡していろいろ加工することができる

3.バインドせずに setText ノードを使う

  エンジンが値を見張ることがないので処理の負担が軽い

 

頻繁に値が変わる場合は、1か2が向いていますが、今回作ろうと思っているのは内容がほとんど書き換わらないので、3にします。

↓テキストをもらって書き換える関数です。

f:id:hiyokosabrey:20170218224228p:plain

 ForceLayoutPrepassノードと getDesireSizeノードのコンビネーションで新しいテキストブロックのサイズを取得します。右端の関数は、親のキャンバスパネルのサイズと比較してスクロールするかどうかをチェックする関数です。キャンバスパネルに収まらなかった場合のみスクロールできるようにしたいので比較してフラグを立てます。

f:id:hiyokosabrey:20170219223606p:plain

ついでにスクロールの限界位置を計算して変数に入れておきます。

 

フラグが立ったら

 フラグといってもブーリアン型の変数です。それをEventTick に Branchノードでつないでやります。スクロールが必要ない場合は処理を省けます。

スクロールが必要な場合は、キー入力を受けてスクロール処理をします。

f:id:hiyokosabrey:20170219225459p:plain

入力チェックのマクロはこんな感じ。

f:id:hiyokosabrey:20170218233113p:plain

Was Input Key Just Pressed ノードは、EventTickのように細かく処理が流れてくるところにつないで使います。Get Player Controller ノードがないと使えないので注意。

ゲームパッドとキーボードのカーソルキーを両方扱えるようにしたいので、OR(論理和)ノードで判定してます。

関数は出口が一つだけど、マクロだと分岐できるのでこういった場合とても便利です。

スクロールするために用意した関数は3つ。スクロール量を計算する関数2つと、実際に動かすための関数になります。

f:id:hiyokosabrey:20170219230322p:plain

f:id:hiyokosabrey:20170219230331p:plain

最終的に、青いノード(Vector2D)に移動後の値(目的地)が入るようにします。

キー入力のたびに上の関数が呼ばれ目的地が瞬時にセットされます。で、常時処理されるのがこの関数↓

f:id:hiyokosabrey:20170219230803p:plain

目的地から現在地の差分に0.1を掛けて現在地に加算したものを新しいポジションとしてセットします。これで常に目的地に向かって移動し続けます。0.1は速度の調整用として掛けています。

 

完成

f:id:hiyokosabrey:20170219231224p:plain

 試しに、シャーロックホームズの冒険(英語)から”ボヘミアの醜聞” の冒頭を流してみました。いい感じにスクロールできます。フォントは Canterburyという書体です。

f:id:hiyokosabrey:20170219231545p:plain

 無事ちゃんと動いていますが、まだ先があるのかわからないので、UIとしてはまだ完全ではないです。スクロールバーか、▼表示か、好みが分かれるところです。あと、上下の端に辿り着いたときに、ループさせるか否かも悩ましいところです。ということで今回はこの辺にしておきます。

ではでは

ステキなスクロールライフを

 

【おまけ】小数点でハマった

最初1行ずつスクロールしていたのですが、行数が多くなると誤差が出てきたり、端までいったときの判定が難しかったりで、結局 固定のスクロール量にしました。それほど悪くないと思います。同じ値を足し引きしてるはずなのに、数値が 0.0000008 みたいなことになるので、< >を使った判定が思うようにいかず頭をかかえることに・・・

 

【補足】うまくgetDesireSizeで取得できない場合

 まだ原因がよくわかっていないのですが、UMGの編集を開始してからしばらくはタイミングによってはまったくサイズが取得できなかったり、改行する前のサイズが取れてしまうようです(私の環境のせい?)。

 そこで確実に改行後のテキストブロックのサイズが取れる仕組みを見つけようといろいろ接続を試してみました。EventTickにつないでチェックすると間違いなく取れます。

f:id:hiyokosabrey:20170218215800p:plain

 DoOnceノードを使って処理をしたりしなかったりをスイッチングします。

 (このあたりいじってたら、いつのまにか、なくても取得できるようになってました・・・)