みつまめ杏仁

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

チャットUIを作る

8

 近くに窓が無いので外の様子が分からないが湿度が高い。帰るまでに雨がやんでるといいんだけど。エレベータを待つ間、ホットにしようかアイスにしようかな迷ったけど、それほど喉が渇いているわけではなかった。少し体が冷えた感じがするので軽くストレッチをして戻ることにする。

 画面丸ごととなると表示するものが多いから結構かかるよな。今日どこまでいけるかな。フキダシの見た目だけでももうちょっと何とかしておきたい。そんなことを考えながら伸びをしていると、カゴが到着する音が鳴って慌てて体勢を整える。ボタンを押してたのを思い出した。幸いドアが開いたけど誰も乗ってなかったので、無駄に乗らなくて済んだ。

 

 さて、まずはフキダシにシッポを付けないとな。Photoshopをアクティブにするとフキダシの作業用ドキュメントが開いたままになっていた。左側のフキダシがデフォだから、画像サイズを右寄せで拡張して、88x64pxくらいかな。

f:id:hiyokosabrey:20190831201733p:plain

 シッポを付けたいけど、ちょっと角削りすぎたか。調整して・・・

 

 サイズが可変にできるよう Boxで指定しているので、分割位置を小数で割り切れるように調整するのが面倒だったけど、どうにかできた。

f:id:hiyokosabrey:20190831203022p:plain

 これをそのまま上書きして、Reimportする。

 

 Reimportしたら、フキダシWidgetを開いて、パラメータを書き換えないといけない。

 分割の指定はMarginのところで行う。まず、左上から Left と Top が 0.625 なので、残りは どちらも 0.375だ。

f:id:hiyokosabrey:20190831205916p:plain

 やっぱり少ない桁で割り切れると気持ちいいな。職業柄 UVを扱って長いので小数点耐性には自信がある。UI制作では小数点で指定することが多かったからだ。そういえばカラーも最近は 0.0~1.0で扱う機会が増えている。

 

 テキストの位置がずれたので、SizeBox にある Paddingで調整する。

f:id:hiyokosabrey:20190831212102p:plain

 ここに、顔アイコンも入れておくか。サイズは 80x80 くらいでいいかな。

 その分、フキダシとSizeBox を右に移動。

f:id:hiyokosabrey:20190831212949p:plain

  フキダシはOffsetX、SizeBoxはPositionXに80を入力する。

 

 ひとまずこの辺でいいだろう。編集モードをグラフに切り替えて、新しく変数を追加する。顔アイコンを受け取るためだ。Textrue2D 型で、Expose on Spawn にチェックを付ける。

f:id:hiyokosabrey:20190831222832p:plain

 コンパイル時に警告が出るので、 Instance Editable にもチェックを付けておく。

 キャンバスに追加した顔アイコンのパーツをGetで配置して、EventConstruct の最後でテクスチャをセットする。

f:id:hiyokosabrey:20190831223319p:plain

 Set Brush from Texture ノードに、さっき用意した変数もつなぐ。

f:id:hiyokosabrey:20190831223608p:plain

 これで受け取り準備完了。

 いったんコンパイルして保存しておく。

 

 

 レイアウトWidgetに戻って、フキダシWidgetを追加するイベントを確認。Create Widgetノードの上で、Refresh Nodes を行うと、ピンが増える。

f:id:hiyokosabrey:20190831224114p:plain

f:id:hiyokosabrey:20190831224349p:plain

 ここに顔アイコンのテクスチャをストラクチャから取り出して渡せばいい。

f:id:hiyokosabrey:20190831224845p:plain

 コメントのテキスト入力ピンが New Var 0 のままだな。ついでに変えておけばよかった。

 

 この辺で様子を見てみようかな。

f:id:hiyokosabrey:20190902214516j:plain

 しまった! 横着してたの忘れてた。テキスト入力用の下敷きを専用で作ってやらないと。

 

 ・・・

 

 気を取り直して再生。適当に入力して試してみる。

f:id:hiyokosabrey:20190902221001j:plain

 右側の時だけ、並びを逆にしたいな。さてやり方はどうしよう。

 

 思いつくのは2つ。今フキダシWidgetを「左専用」にして、新たにフキダシWidget「右専用」を作るか、Widgetは増やさずに今のフキダシWidgetの中でレイアウトをタイムリーに「スイッチ」する処理を追加するか。

 

 ひとまずスイッチするのを考えてみよう。フキダシWidgetを開いて編集モードをグラフにする。isLeft のフラグを受け取ってから左右だけ入れ替えるマクロでも作って入れよう。その前に、フラグを受け取る変数を用意しておかないと。これもExpose on Spawn だな。変数名は、アセットが違うので同じで大丈夫。

f:id:hiyokosabrey:20190902225431p:plain

 まずこれでコンパイルして保存。あ、ついでに New Var 0 だった変数名も変えておこう。テキスト型の変数を、commentBody に変更して、改めてコンパイルして保存する。

 レイアウトWidget を開いて、CreateWidgetノードを確認してみると、New Var 0 のピンが赤くなってる。f:id:hiyokosabrey:20190902231151p:plain

 右クリックして Refresh Nodes すると色が戻った。接続が切れるのでつなぎなおして、増えたピンにストラクチャの isLeft をつなぐ。

f:id:hiyokosabrey:20190902231614p:plain

 これで、左か右かのフラグがフキダシWidgetに渡されるようになった。レイアウトWidgetコンパイルして保存。

 

 再びフキダシWidgetを編集。スイッチ用のマクロを作ろう。名前は switchSide でいいか。

f:id:hiyokosabrey:20190904212655p:plain

 Inputs と Outputs に Exec ピンを一つずつ追加。

 これを Event Construct のところに差し込む。

f:id:hiyokosabrey:20190904212948p:plain

 さて肝心の中身だけど、どうしようかな。ひとまず左右反転してみるか?アンカーいじるのややこしそうだし。Render Transform でひっくり返してみよう。中のテキストはもう一回ひっくり返せば元の見た目に戻るはず。裏の裏は表だ。ひっくり返すのはこいつら。

f:id:hiyokosabrey:20190904213414p:plain

 左右どちらかというのは、 ブーリアンの変数 isLeft が受け取っているはずだから、そこから select ノード使えばいけそう。2つの状態に応じて値を振り分けるのはSelectノードが本当に便利だ。 isLeft が false の時だけひっくり返せばいいから、

f:id:hiyokosabrey:20190904213727p:plain

 こんなとこかな。フキダシWidgetの編集は完了。

 

 さっそく試してみよう。

f:id:hiyokosabrey:20190904214315j:plain

 おお!いいねいいね。

 あ、そうか。顔アイコン白いままだから気にならなかったけど、顔アイコンとかもひっくり返さないといけなくなったな。ひっくり返すものが増えてくると、罪悪感みたいなものが膨らんでくる感じがする。SizeBoxのアンカーを右にしたときにうまくいくか試してみないとわからないな。フキダシの大きさを可変にしたから難易度が上がってしまった。アンカーの設定から見直す必要がありそうだ。この辺は追々詰めるとして、今は先に進もう。

 

 顔アイコンのダミーでも用意してみるか。なんかフリーで使えそうなのないかな。

 しばらくネットを検索結果を行ったり来たりして、まぁ結局いつものとこで調達。ほんとにいつもお世話になってます。手を合わせて心の中でいただきますと呟く。

 透過のPNGPhotoshopでリサイズ。たくさんあるアセットの設定変更は、Asset Action > Bulk Edit via Property Matrix... が便利。一度Importしてから、コンテンツブラウザ上でまとめて選択して右クリックメニューから選ぶ。画像を用意するのに時間がかかったけど、16個のインポートはサクッと終わった。

f:id:hiyokosabrey:20190904224419p:plain

 このアイコンたちを、レイアウトWidgetからフキダシWidgetに渡せばいいだろう。今は左右の矢印ボタンをクリックすると、テキスト入力Widgetとバインドしてイベントディスパッチャーで受け取ってるところがある。そこからフキダシの追加を実行している。

f:id:hiyokosabrey:20190904225649p:plain

 まだテスト用だから、コメント入れておこう。イベントの名前も CustomEvent_0 のままだと役割が分かりにくいので、recieveComment に変えておく。

f:id:hiyokosabrey:20190904230732p:plain

 ここのMakeノード(ストラクチャ用)にテクスチャ2D型のピンがあるからここにつなぐ。そのためにまずはテクスチャを配列にでも入れようか。新しく変数を追加して配列にする。一度コンパイルしてから、16個分の+ボタンをクリックしてエレメントを増やす。テクスチャはプルダウンから選んでもいいし、コンテンツブラウザからドラッグするか、矢印ボタンを使ってもいい。

f:id:hiyokosabrey:20190904231648p:plain

 数が少なければ検索するけど、多いのでドラッグしよう。

 

 配列が用意で来たらグラフに取り出して、GetノードとつないでMakeノードにつなぐ。このままだと 0番のテクスチャしか使われないので、雰囲気を見るためにランダムノードを使う。f:id:hiyokosabrey:20190904232927p:plain

 さっそくテストしてみよう。

f:id:hiyokosabrey:20190904233454j:plain

 かなり雰囲気出てきた。どの顔が出るかわからないながらテキストを打ってみたけど、男の子?以外はキレイに左右に分かれてしまった。うん、確かに顔の向きが反転されていない。

f:id:hiyokosabrey:20190904234048j:plain

 マクロに顔アイコンのパーツも追加するか。

f:id:hiyokosabrey:20190904234213p:plain

 これでどうかな?同じ顔が出るようにランダムノードいったん外して見てみよう。

f:id:hiyokosabrey:20190904234630j:plain

 OK。じゃこの流れでUIDも追加しよう。

 

 テキストブロックをフキダシに追加して、パーツの位置を調整。文字の色はこんな感じかな。小文字が使えたはずだから、ディセンダに注意しないといけない。gyjを追加してみる。

f:id:hiyokosabrey:20190907083331p:plain

 ちょっと被るけど、これくらいならいいかな。ベースラインから下に伸びる文字はいくつかあるけど、意図的に組まない限り出現頻度はそれほど多くない。そこを心配してベースラインがフキダシから離れる方が塊り感が弱くなるのでよろしくない。離れていても、アウトラインや下敷きでグルーピングする方法も採れるけど、チャットなので、縦方向に積み上がっていくことを考えると、あまり上下に無駄な空間は作りたくはない。まぁ画面が採用されて本実装となったら、このまま微調整するか、デザインを見直してもいい。

 TextBlockは Size to Content にチェックを付けておく。これは、サイズを固定すると、余白ができるし、反転した時見た目のズレを、修正する処理が必要になるからだ。

 

 キャンバスはこれでいいとして、UIDを受け取る変数を追加しないと。

f:id:hiyokosabrey:20190907091107p:plain

 これも、Expose on Spawn と Instance Editable にチェックを付けておく。

 次はグラフに、これを書き換える処理を追加しよう。場所は EventConstructの最後に追加でいいかな。

f:id:hiyokosabrey:20190907092007p:plain UID文字列の内容によってフキダシの高さは変化しないから、一番後ろで大丈夫だろう。で、反転対策を入れれば出来上がり。switchSideマクロを編集する。

f:id:hiyokosabrey:20190907092449p:plain

 

 フキダシWidgetの編集は一旦完了。受け取る方の準備ができたら、つぎは値を渡す方。レイアウトWidget の CreateWidgerノードをリフレッシュする。

f:id:hiyokosabrey:20190907093343p:plain

 だいぶ混線してきたな。そろそろ、受け取るフキダシWidgetの変数もストラクチャにした方がスッキリしていいかもしれない。よし一気にやってしまおう。

 

 

 フキダシWidgetスッキリ受け取り改造作戦開始。

 まずフキダシWidget側に変数を追加。もちろん Expose on Spawn と Instance Editable にチェック。

f:id:hiyokosabrey:20190907094422p:plain

 つぎにバラバラと個別に追加した変数たちを、グラフから取り除きつつ、このストラクチャから取り出してつないでやればいい。まずはマクロのブーリアン型 isLeft。マクロの中ではなく、外から入力ピンとして受け取れるようにする。

f:id:hiyokosabrey:20190907094708p:plain

 

 ストラクチャの内容を取り出してつないでいくんだけど、どうしようかな。

f:id:hiyokosabrey:20190907095325p:plain

 ここから、あちこちにラインが伸びていくのが想像できる。そうだ、これを個別の関数にしてしまおうか。いったんこれを Collapse to Function する。

f:id:hiyokosabrey:20190907095636p:plain

 関数名は getSideFlag としておこうか。Return ノードを取り出して、そこへストラクチャの isLeft だけを刺してやる。

f:id:hiyokosabrey:20190907100605g:plain

 関数の仕事結果を返す Returnノードは、ピリオドで検索できるので便利。この関数をイベントグラフのマクロのところにつないでやる。

f:id:hiyokosabrey:20190907100833p:plain

 同じように、他のコメントや顔アイコンのテクスチャとかを関数化しよう。関数って複製できたかな。どうやらできるみたい。

f:id:hiyokosabrey:20190907101029p:plain

 ばばっと複製して、Outputs のピンを差し替えればよさそうだ。Duplicateすると関数のグラフに切り替わって、関数名の変更を要求してくる。このあたり、良く設計されているなといつも感心させられる。エディタ作業においてのヒューマンエラーが時間のロスであることを心得ているかのようだ。実際にプロジェクトで使われて叩き上げられてきた結果だろう。

 コメントとUIDについては表示するときにText型にするので、この関数内でキャスト(型変換)しておこう。

f:id:hiyokosabrey:20190907101822p:plain

 一度String型のまま Returnノードに刺して、出力ピンを作ったあと、接続を切って、Detailタブから変数の型をText型に変える。そして改めてストラクチャのBreakノードからつなぐとキャストノードを入れてくれる。こうするとReturnノードの出力ピン名が分かりやすくなる。まぁReturn Value のままでも不都合があるわけはないので好みの問題か。

 イベントグラフに戻って関数をつなぐ。

f:id:hiyokosabrey:20190907102024p:plain

 この調子で差し替えていこう。

f:id:hiyokosabrey:20190907102757p:plain

 スッキリ。

 全体を眺めてみる。

f:id:hiyokosabrey:20190907102938p:plain

 これで、使わなくなった変数を消してフキダシWidgetの編集終了だ。

 

 さて、次はレイアウトWidgetを開く。

 

f:id:hiyokosabrey:20190907103208p:plain

 予想はしてたけど、ちょっと禍々しい感じ。ここは Refresh Nodesの出番だな。

 

f:id:hiyokosabrey:20190907212634p:plain

 

 Breakeノードは isLeft を別のところで使っているので、ノードをなくすことはできないけど、▲ボタンで少しだけ縮めることができる。

f:id:hiyokosabrey:20190907213126p:plain

 かなりスッキリできた。やっとテストできる。

f:id:hiyokosabrey:20190907220808j:plain

 よしよし。今のところいい感じに進んでる。にやけそうになりながら、適当なコメントを入力して一人チャットを楽しんでいると、後ろから声をかけられた。

「どうすか?」

 谷山田か。「おう」と軽く返事をしつつ手を止めて振り返る。

「メッチャできてるじゃないすか?僕もちょこっとだけ触ってみていいすか?」

 座ったまま少し横に移動し、キーボードの前を開けてやると彼は軽快にキーを叩きだした。

「いいすね。メッチャそれっぽい!」

 後は、と言いかけた時、

「鳥囃子さんに見てもらいましょうか?」

「いや、まだできてないとこあるし。もうちょっと」

 まだ見せられるとこまでできている実感がなかったところへ、突然見せようと言われると躊躇してしまう。確かにある程度のチャット感は出てきたと思う。谷山田が声をかけてきたのは、それが顔に出てたのかもしれないな。

「試してみたいことあるし、形になったらまた声かけるよ。」

 こういった返事は、こちらがいいって言うまで見るんじゃねぇよ、という意味合いを滲ませてしまうので、違う言い方にすればよかったと、口に出してから気づく。

「ですよね、突然ですみません。」

 なんとなく察したか。

「楽しみにしてます。それはそうとして、相談があるんですけど。」

「?」

「スタンプを送れるようにできたらなぁと思うんスけど。いけます?」

 なるほど、これが声をかけてきた目的か。とりあえず即答は避ける。

「うーん。そうだなぁ。」

 UMGのテキストは途中に絵文字やアイコンを混ぜるのは難しい。どちらか一方のみの送信なら。

「コメントかスタンプか、モード切り替えみたいにしていいならそんなにかからないと思う。」

 谷山田の顔がぱっと明るくなった。

「まじっスか?じゃぁまたどんな感じになるかできたら、ちょこっと見せてもらっていいスか?」

「わかった。ところで、そのスタンプ誰が描くの?」

 今のプロジェクトチームにUI担当は自分しかいない。イラストを描くようなデザイナーは今キャラ作成に追われて余裕がないはずだ。 なんとなく自分にお鉢が回ってきそうな気がしたので確認してみる。

「実は鳥囃子さんから聞いた話ですけど、チャットやるならスタンプが欲しい、とプロデューサーが言ってきたそうなんス。ご褒美アイテムとか限定プレゼントとかで使えそうじゃん。て言われたとか。」

 ま、ありそうな話だ。まだ肝心な答えを聞いてないので、だまって次を促す。

「で、もちろん人くれるなら、って鳥囃子さんが条件を付けたそうなんですけど、わかったと。」

「トリさんもやる前提かよ。」

思わずニックネームが出てしまったが、突っ込みを入れたくなったのですかさず返す。

「チームポテイトがいったん企画から練り直しになったんで、デザイナーを一時的に開放するらしいんス。」

 あ、チームポテイトといえば立木坂のいるとこじゃなかったか?まぁエンジンの選定に悩んでるような状態って聞いてたし、あまり健康的にビジョンがまとまってなかったんだろう。

「そこから引っ張ってくるそうです。」

「わかった、こころの準備しとく。まずは今のやつを整えてからで。」

「じゃぁ、よろしくお願いしま~す。」

 そう言って自席に戻って行った。

 

  やることが増えた。まだモックを作り始めて1日も終わってないのに。本実装の前だからまだいくらでもやりようはあるし、その分柔軟な仕様拡張への準備だってできる。「できた!」って言ってから「実は・・・」と後出しするよりはいい。と考えると、若干もやもやするが、今でよかったと納得することにしよう。

 作業を再開しようとモニターに目を向けると、メッセージが届いたというポップアップが画面の隅に現れた。誰だろう? 立木坂?

 

つづく