みつまめ杏仁

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

チャットUIを作る

7

 調べてみたら、テキスト入力を扱った記事が見つかった。思ってたよりむずかしくなさそうだ。よしさっそく参考にしながら作ってみよう。そういえば、入力のスタイルを2種類作ってみる、などと谷山田との会話で豪語していたのを思い出した。仕方がない、まずは中央のボックスバージョンからつくろう。

 

 画面のラフデザインはこれだ。

f:id:hiyokosabrey:20190511100114j:plain

 

 新しくWidgetを作成する。名前は wb_WriteBoxCenter にしておこうか。下敷きの見た目はフキダシ用のテクスチャを代用する。あと左右の矢印ボタンを用意すれば作れそうだ。

 

  Photoshopで右向きの矢印を作る。べき乗が大好きなので大きさは 64x128px。左向きは反転すればいい。背景と距離感を出すためにフチドリを付けておこう。

 f:id:hiyokosabrey:20190819234606p:plain

  デザインはテクスチャサイズいっぱいまで詰めない。何事もゆとりは大事。

 

 テクスチャをインポートしたら、新しく作った Widget を開く。まっさらなキャンバスに向かい合いレイアウトのイメージを頭に思い出す。画面の下にそれほど占有しないので、フルスクリーンのキャンバスは必要ないだろう。エディタ右上の設定を変更する。画面のラフデザインから大体のサイズを測ってキャンバスサイズとして設定。

f:id:hiyokosabrey:20190820000828p:plain

 これでUMGに最初から置かれているデフォルトの CanvasPanel のサイズが変更できる。

f:id:hiyokosabrey:20190820001126p:plain

 

 ここに下敷きと、左右の矢印、テキストボックスを配置していこう。

 まずは 下敷きを中央に。Image を置いて、テクスチャにフキダシで使っているやつをセットする。自分専用なのでカラーを変えておこう。配置はストレッチにするけど、左右にボタンをおくから余白を開けておく。

f:id:hiyokosabrey:20190820233644p:plain

f:id:hiyokosabrey:20190820234243p:plain

この設定にしておけば、あとからキャンバスのサイズを変更しても追随するから安心。


 次は左右の矢印。矢印はクリックを受け付けるので、Imageではなく Buttonで配置する。テクスチャと同じくサイズを64x128にしてレイアウトしておこう。

f:id:hiyokosabrey:20190821011755p:plain

 アンカーを右端中央にして、Pivotを(1.0, 0.5)にして、Positionを (0, 0)。あとは、Buttonに画像をセットする。ふるまいに合わせて画像を変えられるけど、今回は同じ画像にしてカラー変更で対応しておこう。通常時の Normal、マウスカーソルが乗った時の Hovered、そしてクリックしたときのPressedの3箇所に矢印のテクスチャ画像をセットする。

f:id:hiyokosabrey:20190821013224p:plain

 右側ができたから、このButtonを複製して左側に配置する。今度はアンカーを左端中央にして、Pivotを(0.0, 0.5)にして、これもPositionを (0, 0) にする。

f:id:hiyokosabrey:20190820004505p:plain

 左側の RenderTransform の Size X を -1.0 にして左右を反転すると、

f:id:hiyokosabrey:20190820004815p:plain

 よしできた。

 あとは、この上にテキストボックスを載せるだけ。えっとどれだっけ?

EditableText (Multi-Line) こっちだな。

f:id:hiyokosabrey:20190821010250p:plain

 これも下敷きと同じようにアンカーはストレッチでいこう。フォントとMarginを設定して、

f:id:hiyokosabrey:20190821010600p:plain

 よし。こんなもんでいいかな。ヒエラルキーはこんな感じになった。

f:id:hiyokosabrey:20190822225631p:plain

 いったん保存して、レイアウトしてみよう。

 

 レイアウト用のWidgetを開いて、User Created のカテゴリから、作ったばかりのテキスト入力Widgetを探すとすぐに見つかった。早速キャンバスに配置する。

 

あれ?

f:id:hiyokosabrey:20190823232533p:plain

 Size To Content にチェックを付けるとつぶれてしまった。あのエディタ右上のキャンバスサイズはあくまでも作業のための設定ということか。仕方がないので手入力でサイズをセットする。 アンカーは中央下端。

f:id:hiyokosabrey:20190822230218p:plain

 試しに変なサイズにしても、ちゃんと問題なく合わせてくれる。

f:id:hiyokosabrey:20190823233236p:plain

 

 

 再生してみると、特に問題なくレイアウトが確認できた。

f:id:hiyokosabrey:20190823002220j:plain

 さて、ボタンをクリックしたときにメッセージをサーバーに飛ばすことになるんだけど、そういえば、左右の振り分けとテキストの送信については相談してなかったな。

 席を立ち、プログラマの南河原さんのところに向かう。プロジェクトがまだ小規模なので、そんなに席が離れていない。背後からおつかれさまですと声をかける。

 「今、大丈夫ですか?」

 彼はコードを吟味していた手を止め「はいはい。」と振り向いた。

 そこで、

 「例のチャット表示を作ってるんですけど、」と切り出し、ユーザーの発言毎に、画面の左右に表示位置を振り分けたいということと、そのユーザーが任意で右か左かを選べるということを再度確認の意味を込めて話した後、

 「テキストと一緒に左か右かの情報をくっつけて送ることになると思うんですよね。もう準備とか始められてたりします?」

 「いや、まだなんも手ぇ付けてない。来週あたりサーバー担当と話しよかなって。」

 うーん、と言ってつかのま考えてから、

 「そうやなぁ、他にも ユーザーID とかアイコン情報とか諸々決めなアカンねんけど、すぐ決めた方がいい?」

 そう訊かれたので、

 「いえ、大丈夫です。プロトタイプなんで適当にやっときます。」

 と答えると、

 「ゴメンな。決まったらまた共有するし。」

 「はい、お願いします。」

 

 ということで、自席に戻って考えてみる。おそらくサーバーへ送信するための関数を用意してもらえると思うので、それをイメージしたテスト用の関数をこちらで用意しよう。あとは受け取り用のフキダシ追加イベントのパラメータを拡張していけばいいだろう。

 今は実装方法を詰めたいわけではなく、とにかくプロトタイプを触って操作感や挙動について検証し、最終的なゴールをプロジェクト内で共有するのが目的だ。そこで見つかった問題を解決し、「余分」と「余白」について検討する。「余分」は「余白」を最大化するための伸びしろだと捉えるようにしている。一方の「余白」は将来の「余裕」と見るか、「不足」と見るかは判断が難しいところだけど、仕様変更や調整の波をかぶりやすいUIにとっては「保険」という意味合いも含ませていいと個人的には考えている。他人には「物足りない」という印象を与えてしまうリスクがあるけれど、「あ、まだ仮なんで」という決めゼリフがあるので問題ない。ちなみにこの決めゼリフを本実装のあとで吐くことになると辛い。声が震えるのを抑えながら言うことになる。

 

 さてと、フキダシとしてサーバーから送られてくるコメントを表示するにあたって、フキダシWidgetが欲しい情報で思いつくのは以下の 5つ。

 

 ①ユーザーID

 ②コメント本文

 ③左か右

 ④顔アイコン

 ⑤自分かどうか

 

 ローカライズはしないのと、加工や整形ができるので ①と②はString型でいいと思う。③と⑤は選択肢としては2つしかないのでBoolean型でいけそう。④はTexture型で。ひとまずこれでストラクチャを使ってみよう。

 

 ストラクチャはコンテンツブラウザで右クリック、Blueprints の中にある。

 chatComment と命名。あとでちゃんとしたやつが来るので、それまでの暫定ネーム。

f:id:hiyokosabrey:20190824204134p:plain

ダブルクリックして中身を編集。

f:id:hiyokosabrey:20190823235936p:plain

 保存して、レイアウト用Widgetに戻る。

 

 まずセットするのは、フキダシを追加するイベントのところ。

f:id:hiyokosabrey:20190824001605p:plain

 イベントノードをフォーカスして、Detailsタブの項目 Inputs からピンを追加する。型は、さっき作ったストラクチャの名前で検索するとリストから見つかるのでそれを選択。

f:id:hiyokosabrey:20190824203838p:plain


 適当に名前を付けると、カスタムイベントのノードに濃い青色のピンが追加された。

 ストラクチャは、複数のデータの寄せ集めな状態なので、一つのピンから情報を個別に取り出す必要がある。そこで Breakノードの出番。

f:id:hiyokosabrey:20190824211609g:plain

 

 Breakノードで分解されたピンから、ストラクチャで自分が追加した CommentBody があるので、選んでダミーテキストをつないでいたところに刺す。

f:id:hiyokosabrey:20190824204640p:plain

 String型とText型は型が違う。このように違う型同士をつなぐ場合、キャスト(型変換)してからつなぐのが儀式なんだけど、UE4のブループリントエディタは直接つなぐことができて、さらに自動的にキャストノードを間に入れてくれるので、ラクチンだ。

 よし、このままフキダシの左右レイアウト対応もやっておこうか。

 まずはダミーコメントの表示で使ってたカウンター処理を外す。

f:id:hiyokosabrey:20190824212844p:plain

 この右端の外したところに、水平方向のレイアウトで、右寄せ、左寄せを決める set Horizontal Alignment ノードをつなぐんだけど、えっとどこからだっけ? VerticalBoxの設定になるから、Add Child to Vertical Box ノードにある、Return Valueから探せば、あ、あったあった。

f:id:hiyokosabrey:20190824213423p:plain

 なんだか、Vertical(垂直)、Horizontal(水平)と混ざり合ってややこしいけど、カテゴリが、 Layout > Vertical Box Slot になってるからここで間違いない。

 出てきたノードをつないで、ラインを整える。

f:id:hiyokosabrey:20190824214406p:plain

 で、この濃い緑のピンにつなぐのは、ストラクチャの isLeft というBoolean型のピンだけど、こんなときは Select ノードの出番。この濃い緑のピンからドラッグして、Select で検索する。

f:id:hiyokosabrey:20190824220501p:plain

 いい感じにノードが見つかって取り出すとき、思わずドラえもんの声真似をしてしまう。大丈夫、声には出てない。このSelectノードの 一番下にあるピンとストラクチャに設定した isLeft ピンとつなぐ。

f:id:hiyokosabrey:20190824221334p:plain

  どう見ても、Integer型のピンだし、Index って書いてあるけど、ここも気にせずつなげることができる。先にプルダウンを開けてBooleanに変えておいてもいい。

 

f:id:hiyokosabrey:20190824222020p:plain

 つなぐと、Selectノードの 左にある入力ピンのラベルが変更される。isLeft の内容が True なら 左。Falseならその逆の右 になるので、それぞれのプルダウンを変更する。

f:id:hiyokosabrey:20190824222518p:plain

 これで、コメントのフキダシが左右に振られるようになったはず。

 

 

 ここで、現状のコメントが表示されている流れを確認しておこう。

 

 スペースキーが押されたかどうかの検出を、レベルブループリントで行っている。

キー入力系のイベントは、Widget内に置けないからだ。

 

f:id:hiyokosabrey:20190825125518p:plain

  レベルブループリントから、レイアウトWidgetにあるフキダシ追加の関数を呼び出され実行している。コメントはダミーで、レイアウトWidgetが内部で持っている。

f:id:hiyokosabrey:20190825125754p:plain

 

 ここまではコメントの表示方法を検証してきたのでこれでも問題なかったけど、コメントを作成して送る表示ができたので、この仕組みを変える必要が出てきた。

 

 受信時はレイアウトWidget経由で、コメントが渡されることになるのは今の状態とそれほど変わらない。一方の送信時はテキスト入力Widgetがトリガーとなって最初に動くことになる。だから機能として追加しないといけないのが、テキスト入力Widgetからの送信を受け付ける流れ。

f:id:hiyokosabrey:20190825161213p:plain



 フキダシWidgetから親であるレイアウトWidgetに通知するには、イベントディスパッチャーで行う。コメントを入力し終わって、左右のボタンをクリックしたら、入力した内容と左右どちらのボタンを押したかの情報を共に通知する。

 

 さっそく、イベントディスパッチャーを追加する。

f:id:hiyokosabrey:20190825161614p:plain

通知するパラメータに Boolean型の isLeft 、String型の commentBody 2つを追加する。

 

 このイベントディスパッチャーを呼び出すのは、左右ボタンをクリックした時だから、OnClicked のイベントを用意しよう。Buttonで作っておいたので、イベントの追加は簡単だ。

f:id:hiyokosabrey:20190825162725p:plain

 緑のボタンをクリックすると、イベントノードをグラフに置いてくれる。

f:id:hiyokosabrey:20190825162936p:plain

 ここにさっき追加したイベントディスパッチャーを ”Call” のカタチで呼び出してつなげる。このイベントはすでに右か左かハッキリしてるので、isLeft のところもあらかじめチェックを付けておくことができる。

f:id:hiyokosabrey:20190825163439p:plain

 あとはにコメントの内容をゲットしてつなげれば出来上がりだ。

 

 コメント自身は、MultiLineEditableText が持っている。そこからGetしよう。

f:id:hiyokosabrey:20190825164251p:plain

 これ最低限の処理はできたけど、判定とかも加えたいので、さらにこれをマクロにする。マクロの方が関数より分岐がやりやすい。GetText~ノードとキャストノードをフォーカスしておいて、右クリック > Collapse to Macroだ。

f:id:hiyokosabrey:20190825165445p:plain

 

 できたマクロを編集する。

f:id:hiyokosabrey:20190825165817p:plain

 まずは、Inputs に Execute ピン を追加する。同じくInputs にある Self ピンの名前を変えておく。 EditableText あたりでいいだろう。

f:id:hiyokosabrey:20190825170420p:plain

 ブランチノードを追加して、Execピンとつなぐ。

f:id:hiyokosabrey:20190825170811p:plain

 続けてブランチノードの右側のピンを、マクロのOutputsにドラッグ&ドロップする。

f:id:hiyokosabrey:20190825171237g:plain

 ピンの順番はここで変更できる。

f:id:hiyokosabrey:20190825171515p:plain

 今ここで判定したいのは、コメントが空だった場合。

 内容が空っぽかどうかを調べるノードとして Text is Empty ノードが用意されているので、これを使う。

f:id:hiyokosabrey:20190825172021p:plain

 これでマクロはひとまずできあがり。マクロの名前は getSubmitText にしておこう。

 

 イベントグラフに戻ってつなぎなおす。

f:id:hiyokosabrey:20190825172455p:plain

 コメントが空の場合、Text is Empty が True(真) になるので、コメントが入っていると、False(偽)になる。理解していてもイベントグラフだけを見るとなんか気持ち悪い。Outputsのピン名を変えよう。もう一度マクロを編集する。

f:id:hiyokosabrey:20190825173033p:plain

 True を Failur(失敗)、FalseをSuccess(成功)にしよう。

f:id:hiyokosabrey:20190825173147p:plain

 うん。解りやすくなった。

 送信した後は、空にしておかないと。

f:id:hiyokosabrey:20190825195921p:plain

 

 これでテキスト入力Widgetは編集完了。次はレイアウトWidgetでバインドしてコメントを受け取れるようしよう。

 

 レイアウトWidgetのキャンバスに置いた、テキスト入力Widget を グラフに取り出して、ed_submitComment にバインドする。そしてバインドノードの Eventピンからカスタムイベントノードを取り出す。

f:id:hiyokosabrey:20190825200546p:plain

 ここにフキダシ追加イベントをつないでみよう。ひとまず表示テストはできるはず。

 

 フキダシ追加イベント addFukidashi は、コメントをストラクチャで受け取るようにしたばかりなので、渡せるようにMakeノードを使う。

f:id:hiyokosabrey:20190825201353p:plain

  ストラクチャへの受け渡しは、まんま同じ型ならそのままつながるけど、単品で値を書き換えたり読み出したりする場合は、 BreakノードとMakeノードを駆使する。ここでは一部分だけ渡したいのでMakeノードが便利。

f:id:hiyokosabrey:20190825201809p:plain

 

 早速テストしてみよう。

f:id:hiyokosabrey:20190825203309j:plain

 左のボタンをクリックすると、

f:id:hiyokosabrey:20190825203335j:plain

 お、いい感じ。適当に飛ばしてみる。

f:id:hiyokosabrey:20190825203352j:plain

  うん大丈夫そうだ。ちゃんと左右に割り振れてる。できてきた感!

 

 あとは、入力中のテキストに文字数制限処理入れたり、入力中かどうかのハイライト処理とかもあった方がいいかな。その前にいい加減アイコン出せるようにしようか。UIDも出さないとな。フキダシの尻尾もちゃんと作らないといけないし。とりあえず休憩しよう。席を立ち空調の効いたフロアを出る。

 

 

つづく