みつまめ杏仁

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

ポップするリスト表示を試してみたのでメモ

3人称視点のアクションRPGとかで、フィールドに落ちている何かを拾うと、ログ表示のように画面端に表示されるあれです。

原神をプレイしてて作ってみようと思い立ったUI表示ですが目コピーではないです。

f:id:hiyokosabrey:20210106233401j:plain

試そうと思ったきっかけは、

  • VerticalBoxに追加した UserWidgetが、自身を Remove from Parent したらどうなるのか?
  • ガシガシ追加しまくっても、一定時間経過で勝手に消えてくれるのであれば、追加する側が管理しなくてもいいのでは?

 

という安易な推測によるものでした。

 

で実際にやってみた作り方をメモメモ。

 

Widgetを2つ使います。

まず最初に作るのは、表示する子要素であるWidgetから。

f:id:hiyokosabrey:20210104214201p:plain

 

UMGのキャンバスには、まとめてアニメーションさせるための CanvasPanel を追加して、あとはその子供として Image(下敷き用)、Image(アイコン用)、TextBlock(アイテム名など)を配置。

f:id:hiyokosabrey:20210104214320p:plain

f:id:hiyokosabrey:20210104214643p:plain

↑ Image_Cover は登場時に白くフラッシュさせるエフェクト用です。

 

最初から配置されている CanvasPanel は、Canvas Panel Slot を持っていなくてサイズを使ったアニメーションができないので放置。

 

ここでポイントが2つ。

1つは、余白を作っておくことです。
f:id:hiyokosabrey:20210104215511p:plain

画面に見せたいパーツ(中身)の大きさより、CanvasPanelを少しだけ大きくします。

これが並んだ時のスキマになります。

VerticalBox に追加する際に Padding で調整すると、Paddingの余白はサイズのアニメーションに含まれないため、タイミングによってはかカクっとなるのが見えてしまいます。

f:id:hiyokosabrey:20210104224334g:plain ← CanvasPanelに余白

f:id:hiyokosabrey:20210104224408g:plain ← Paddingで余白



アニメーションは、 Open(出現用) と Close(退出用) の2つ。

 

Open

f:id:hiyokosabrey:20210104232906g:plain


Close

f:id:hiyokosabrey:20210104233140g:plain

もうひとつのポイントはここ。

なるべくSizeのアニメーションは最後までとっておきます。

f:id:hiyokosabrey:20210104234459p:plain

先に Scale と Opacity で見えなくしてから、Sizeのアニメーションをさせるようにすると、リストに追加があったときに見やすくできます。

アニメーションで動きをつけるのは、気づきやすさ(視認性)を上げるうえで有利ですが、静止しないと読みにくい(可読性が下がる)ので、調整は大事です。

 

UIを試行錯誤しながら作っているこの状況で、気を付けたいのがこの視認性と可読性のバランスです。

テスト用の文字列やアイコン情報を表示しても、内容については仮のものなので、無意識に表示内容をスルーしています。動きや雰囲気に注意が向いている分、そこさえ良ければ、もう出来た感じがしてしまうという罠です。実装後の確認とチューニングはしっかり行いたいものです。

 

あと、細かいことですが、出現と退出のアニメーションを別々で作っているのは理由があります。

適切な表示時間を、ブループリントでDelay ノードで調整したいからです。

いい感じの表示時間が確定さえすれば、後でタイムラインを一つにできます。

また、表示時間の調整を行う際に、自分以外の方に説明するのが簡単です。

「なんか短くない? 何秒?」

「(Delayの値)1.25秒です」

「2秒にしてみたらどんな感じ?」

「ちょっと待ってくださいね」

てな具合にやり取りができます。

 

というわけでキャンバスはこのくらいにして、続いてWidgetブループリントを編集。

Event Construct

f:id:hiyokosabrey:20210104233602p:plain

右下のノード Remove from ParentSelf を指定しているので、自分自身が消滅します。

 

再生するアニメーションが 2つあるので

上の例では、アニメーション終了検知のイベント は使用しないケース、

下の例は使用するケース。

f:id:hiyokosabrey:20210105235540p:plain

 

いくつかの変数をパラメータとして受け取るようにしています。

f:id:hiyokosabrey:20210105003141p:plain

Expose on Spawn を有効にしているので、この Event Construct が実行される時にはすでにパラメータを受け取っているという段取りです。

f:id:hiyokosabrey:20210105005147p:plain

最終的に Structure にしたほうがよさそうな気はします。

 

表示のためのセットアップは、ブループリントのスクショがコンパクトになるようにマクロにしています。

マクロの外に接続するようにしているのは、自分以外の方、もしくは未来の自分がブループリントを見た時に、少しでも何をしているか、何をしようとしているかを解りやすくするための気配りみたいなものです。

で、マクロの中身はこんな感じです。

f:id:hiyokosabrey:20210105004145p:plain

FormatTextノード便利ですよね。

 

これで表示する子のWidgetは完成です。

 

 ここからは、リストを並べるためのWidgetを作っていきます。

f:id:hiyokosabrey:20210104214209p:plain

 

UMGのキャンバスには、VerticalBox が一つ。

f:id:hiyokosabrey:20210106000647p:plain

 

次にWidgetブループリント

f:id:hiyokosabrey:20210106001444p:plain

簡単なテストということで、変化を楽しむためのカラーを配列に仕込んでいます。

セットしている配列変数は、LinearColor型です。

 

カスタムイベントを用意します。

f:id:hiyokosabrey:20210106002142p:plain

CreateWidgetノードに、先に作ったリスト用のWidgetを Class としてセット。

f:id:hiyokosabrey:20210106003214p:plain

変数の Expose on Spawn を有効にすると、この CreateWidgetノード経由で初期値を渡すことができます。

 

これで出来上がりです。

 

 

あとは適当なレベルを作って表示テスト。

f:id:hiyokosabrey:20210106003758p:plain

Inputノードで、スペースキーを押すと、カスタムイベントを呼び出す。

 

f:id:hiyokosabrey:20210106011549j:plain

Twitterに動画を上げてるので、動きのイメージはこちらから ↓

テキストの表示が TextBlock のままですが、動きは同じになります。

 

一応検証用に、VerticalBoxの子要素をカウントしてみました。

キャンバスに TextBlock を一つ追加して、EventTickで監視した数を常時表示します。

Get Children Countノードを使って調べます。

f:id:hiyokosabrey:20210106011833p:plain

Remove from Parent で消滅するタイミングでカウントが減ります。

f:id:hiyokosabrey:20210106012210g:plain

いい感じに動作しているようです。

 

ガシガシ呼び出しても、勝手に消えていくんで管理する手間が省けていいなぁ、と思いたいけど、実際には表示数に制限が必要だし、制限を越えた分はプールしておいて、空きができたら、プールが空になるまで逐次追加し続けたりしないといけない。

とはいえ、最初の推測通りの結果になったので、よかったよかった。

 

というわけで

今回はこの辺で

 

皆様、健康でよい一年になりますように

 

今年もよろしくお願いいたします

 

雑記

2020年も今日で終わり、明日からは令和も3年ということで、1年間本当におつかれさまでした。このブログも開始から5年が経過しました。記事の数は181。ペースはのんびりですが、よく続いたなぁとしみじみ思ってます。いつも多くの方に閲覧いただいてて、それが嬉しくてとても励みになってます。ありがとうございます。

いろいろと気忙しい状況が続いてて、前回より間が空いてしまいましたが、ぼちぼちやっていこうと思います。

 

 

最近Twitterにあげたやつ その1

星のカービィ スターアライズのプレイ動画がタイムラインを流れてきたので見ていたら急に作りたくなったやつ。

f:id:hiyokosabrey:20201231000113j:plain

f:id:hiyokosabrey:20201231000231j:plain

f:id:hiyokosabrey:20201231000243j:plain

f:id:hiyokosabrey:20201231000253j:plain

f:id:hiyokosabrey:20201231000354j:plain

 場面転換で見かけるやつです。

テクスチャを使わずにやってみようと思って

f:id:hiyokosabrey:20201230235038p:plain

斜めに配置

f:id:hiyokosabrey:20201230235059p:plain

試そうと思ったきっかけは以下の3つ。

  • VectorToRadialValue ノードで円形のグラデが作れるよね
  • Step ノードで円の大きさが変えられるよね
  • UVってタイリングできたよね

この辺りが頭の隅に残っていたのがよかった。

 

途中計算がおかしくてなかなか粒がいい感じにならなかったけど、なんとかサマになってよかった。

SmoothStep を使うばジャギらないのが作れる。

 

あとは、波紋のように変化させたりしたくて、いろいろ試してみたけど、うまくいかず・・・。また方法をひらめいたらチャレンジしよう。

 

2021/1/20 追記 >>

このサンプルは、全画面にかける想定で、パラメータをなるべく減らしてConstantを使うことで気持ち的に処理を稼ぎたかったというのもあって、いろんなサイズの描画にはまったく対応できない作りです。都度マテリアルをいじるか増やすかしないといけないので、汎用性ゼロです。

ところが、ちゃんと汎用性があって、交互に並んでいて、グラデーション表現も可能になったのが紹介されました!

言及ありがとうございます!素晴らしいです > ネリスさん

lunanelis.hatenablog.com

<<

 

 

 

今年読んだ小説

普段通勤時間の暇つぶしのために少しづつ読んでいるんだけど、続きが気になってしまい家に帰っても読んでしまうほど。ハマったのが 知念実希人 の 天久鷹央 推理カルテ シリーズ。平積みで並べられているのを何度も流し見てるうちに、いとうのいぢ のイラストが気になってきて、ちょうど読みたい本が途切れたタイミングで手に取ってしまったのがきっかけで、表紙に惹かれたんだと思うけど、書店の推しに屈した瞬間だった。

というわけで出ている巻全部を大人買いして一息に読み切ってしまった。

 

ときおり挿入される主人公のモノローグのおかげで感情移入しにくいこともあるけど、ストーリーの流れ方がすごく好みだった。医療系ミステリは初めてなので、知ってるものから知らないものまでいろんな症例がトリガーになって起こった経緯を、ラストで鮮やかに説明してしまうところは、駆け付けた居酒屋で飲む最初のビールのような爽快感で病み付きに。著者が現役のお医者さまというか職業柄のせいか、病が人の心に与える影響や、また患者の周囲にいる人々にもメスをいれて、時に生々しく書かれる人間模様はさすがという印象。 個人的に医療への好奇心を満たせたのもよかった。

 

大好きな作家なのに、なぜだかずっと手を付けなかった 米澤穂信追想五断章 を読んで、感銘をうけた。リドルストーリーなるものに興味がわいたので 謎の物語/紀田順一郎(編) を読んでみたり、あまり長編は飽きるので、短編集や編集モノが多かったかな。最近気に入って読んでるのは、上田 早夕里。やっぱりSFは興味深い。

狐と鞭も面白かった。古典もいいな。

結構読んだ気もするけど、タイトルが思い出せるのは少ない。なんかもったいない。

 

若かったころ、敬語はもちろん丁寧語すら怪しかったので、語彙力を上げるために頑張って現代モノの小説を読むようになって今に至る。映像がないからこその楽しみ方があるのがわかったし、好きな作家にも出会えた。書店通いは楽しい。

VRの超巨大図書館とかできないかな。検索で探すのではなく、実際に背表紙を眺めながら歩き回れるような。本のタイトルや装丁から中身を塑像するのも楽しいですよ。

 

 

最近Twitterにあげたやつ その2

なんかマテリアルでビリビリエフェクトみたいなの、以前TLで見たような気がして、試してみようってなったやつ。

f:id:hiyokosabrey:20201231120126g:plain

テクスチャは 8x128

f:id:hiyokosabrey:20201231115836p:plain

カーブアトラスを作ってマテリアルで使う

f:id:hiyokosabrey:20201231115712p:plain

 

ノイズだけだと、全体に暴れるので、

f:id:hiyokosabrey:20201231131916g:plain

両端が0 のカーブを UV の V方向(縦)に対して掛ける

f:id:hiyokosabrey:20201231132311p:plain

f:id:hiyokosabrey:20201231132117g:plain

あとは、UMGにでも貼ればできあがり

f:id:hiyokosabrey:20201231132548p:plain

長さによってブレ幅が変化するので、マテリアルのほうでいろいろ調整が必要だけど、ゲージに乗せると、スタン中の表現として使えそう。

 

 

というわけで

この年末も何かゲームUIネタを書こうかと思ったりしたのですが、うまくまとめられず結局筆が進みませんでした。

以前から携わってたタイトルが、春にリリースされて腑抜けていたのもあるかも。(長いな)

 

レンタルオフィス借りて勉強会~と思ってた矢先での新型コロナ大流行。来年はどうなるのでしょうか・・・まぁいろいろ安全な方法を探っていきたいところです。

 

相変わらず記事のネタは常に探しているところですので、このブログのコメントか、Twitterでも提供いただけると大変助かります。

このゲームのこのUIってどうやって作ってるの?とかももっと書いていけたらなと思ってます。

 

ペースは気まぐれでゆっくりですが

今後ともよろしくお願いいたします。

 

ではでは 皆さま よいお年をお迎えください

 

文字がシャッフルしながら出てきてランダムに消えていくやつについてのメモ

さすがに涼しいと言ってられないほどの気温になってきました。ほんの数日でしたが大好きな稲刈り後の田んぼの匂いと金木犀の香りで秋の深まりを実感している今日この頃です。

 さてさて ちょっと間があいてしまいましたが、先日Twitteにあげたテキストエフェクトについて書こうと思います。

 

 

今回のはブループリントは載せずに、どういった構造にしたかをメモします。

多分もっといい方法がありそうなのと、実際の需要としてはニッチすぎるので、BPの組み方やら、UMGの作りはまず参考にはならないだろうという想定です。

 

ということで、まずはシャッフルしながら文字列がでてくるやつ

 

初めに考えたこと

1文字分だけ表示するWidgetを作ってそこでランダム処理をさせる方法。

ある文字列をバラして、1文字づつをWidgetにシャッフル時間と共に初期値として渡して並べるだけというラクな発想。

f:id:hiyokosabrey:20201029230537p:plain
フォントの選択肢が多いのと、放置プレイできて便利なんだけど、文字数が多くなると、それだけWidgetの生成と消滅が発生するので、ちょっと負荷が心配になるので却下。あとレイアウトも考慮すると管理するWidgetの階層が増えそう。

 

そこで、TextBlock ひとつのままでシャッフルできないか考えてみた。

f:id:hiyokosabrey:20201029230556p:plain

要するに文字列の段階でいかにしてうまくシャッフルの文字列を作るか。

さらに、

  • シャッフルが始まって全部が一斉に止まるのはやりたくない
  • 少しずづ確定させたい
  • 端からではなくランダムに

というのをハードルとして課すことにした。

 

 

あらかじめランダムな文字列を作ってしまえばいいのでは?

文字列を受け取ったら、その文字数分のランダム文字列を先に作り置きして、あとは順番に取り出して表示するという方法を思いついた。なんかよさそう気がする。問題なのは、どうやって少しづつ確定させるか。

年々しぼんでいく脳みそで頑張ってみた結果、配列を使うとうまくいきそうな気配を感じたので試してみた。

まず文字列を配列にバラせるかどうか ノードを漁ってみるといいノード発見。

f:id:hiyokosabrey:20201029232144p:plain

 

String型の配列を用意して、文字数分の要素を確保。

 

f:id:hiyokosabrey:20201030002021p:plain


ここに、ランダムな文字をランダムな文字数ぶん入れて、最後に表示する確定文字で埋める。

配列の各要素に入れる最大文字数は演出時間で調整するとして全部一律。

最大文字を14とした場合。

 

f:id:hiyokosabrey:20201031155422p:plain


紫色の文字がランダム文字、青色の文字が確定文字。

ヨコが配列の要素、タテが要素内に並べた文字列。

あとは表示する際、先頭から順番に取り出して、くっつけて表示する。

f:id:hiyokosabrey:20201031155403g:plain

 

表示してみるとこんな感じ

f:id:hiyokosabrey:20201031161322g:plain

思ってた感じにできた。

 

ランダムと言っても、ある程度幅の調整は必要。

f:id:hiyokosabrey:20201031161617p:plain

ランダム文字の生成は、固定の文字列から一文字を抜き出す方式。

f:id:hiyokosabrey:20201031162554p:plain



 

消えるときもランダムで虫食いっぽく消したい

ランダムの欠点というか残念なところは、同じ数を引いてしまうことがあるとこ。

ランダムに位置を決めたら文字が空白かどうかチェックして、空白じゃなければ消す。空白だったら、再びランダム位置決め・・・ これだと終盤空白だらけになった時、空白じゃない文字を引く確率が下がってしまい、最後まで消えきる時間が不安定になってしまう。

そして思いついた方法が2つ。

一つは、表示している文字がアルファベットと数字だけなので、順番に検索をかけてヒットしたら消すことにすると、確実に一定の時間内ですべて消える。

確実に消えるけど、”WWW”みたいな文字列があると、一斉に消えてしまうのと、法則性が見えてしまいそうなのが無粋かな。

 

でもう一つの方法が、文字列の中で消す順番をランダムにする方法。

順番を決定するための配列を増やすことで対応できそうということで試してみることに。

まず表示している文字列と同じ数の要素を持った配列を用意。

そこへ、0~ 順番に数値を入れていって、最後にシャッフル。

 

f:id:hiyokosabrey:20201031170149p:plain

 

配列の要素をシャッフルしてくれるのがこのノード

f:id:hiyokosabrey:20201031170131p:plain

 

この配列の要素を順番に取り出しながら、表示している文字列を空白に置き換えていく。

文字列操作のノードを駆使してなんとかこんな感じでできた。

f:id:hiyokosabrey:20201031170643p:plain

Leftノードは、文字列の左から指定文字数ぶんをゲット、同様に Rightノードは文字列の右から指定文字数ぶんをゲット。

該当する場所の文字をよけて、切り出すイメージ。

f:id:hiyokosabrey:20201031172632p:plain

 

これで、配列の要素数ぶん(=文字数)この処理を繰り返せば確実に毎ターン一文字ずつ消えていくという寸法。

 

f:id:hiyokosabrey:20201031173653g:plain

 

これで出来上がり。

 

↓これは、Twitterに上げたGIFで 30fpsで撮ったもの。

f:id:hiyokosabrey:20201031173923g:plain

 

一応満足いく形にできた。

 

でもしばらく眺めているうちに 確定したタイミングでもう少しメリハリが欲しいかも、と思ってカラーで変化をつけてみた。

 

f:id:hiyokosabrey:20201031190654g:plain

ビビリだけUMGのタイムラインで、出現時と消滅時は、Lerpノード を使ってるので、文字数によって時間の長さが変わっても大丈夫なつくり。

 

 

とりあえずこれで良しとしよう。

ランダムとうまく付き合うのは、なかなか骨が折れるというか、神経を使う感じですが、UI表示でランダムを使えると楽しいので、頑張ってしまいます。

プログラマーに指定書で細かく書いて渋い顔されて、いざ画面に表示されてからさらに微調整するといった面倒に突き合わせて申し訳ない気持ちになったな時代は遥か彼方。

いい時代になったもんです。

もっと効率のいいやり方とか、賢いやり方があると思うので、共有してくださる方が現れるのを期待して、この記事を書いています。

 

映画の冒頭やアニメのオープニング、ボカロのMVとかで面白いテキスト表現に出会うとうれしくなります。と同時に先を越されたような口惜しさも味わうことになります。

ゲームは動画ではなくリアルタイムで描画するので、インタラクティブな見せ方ができるのが魅力の一つ。映像作品を参考にしたりUE4でいろいろ実験して、テキスト表現のネタを引き出しにしまいつつ日々精進してまいりましょう。

 

ではでは

ステキ な テキストエフェクトライフを!

 

 

雑記

Twitterだと書ききれない、ブログだとボリュームが少なめの内容で書き散らしました。内容は適当なのはご容赦いただけますと幸いです。

 

 

ここ最近風邪っぽくて

いつもと同じものを食べてるのに、あれ?こんな味だったっけ? と、ちょっとした味覚の変化にびくびくしながら過ごしています。 新型コロナじゃない普通の風邪?従来の風邪?だったとしても、大変不安な気持ちになるので早く免疫をゲットしたいですね。昔だったら誰かの祟りとか怨霊の仕業で必死に鎮めようとしただろうな。陰陽師という職業が今も続いていたら、この疫病の原因はなんと答えるのだろうか。などと資料を読みながらいろいろ妄想しています。

 

 

最近『原神』始めました

おすすめポイントはどこかと聞かれれば、景色が綺麗なのとキャラがかわいいのと、あとはそれくらいだったりするのですが、ブログの記事を書かなきゃと思いつつも原神始めてしまうくらいのおすすめ感です。で、コントローラ操作で遊んでいるのですが、ボタン操作のナビ表示をしっかり見てから操作しないと意図しない結果になるので、かなり学習コストが高い印象です。慣れの問題でしょうけど 日系プレステ操作の 〇決定 ×キャンセル のボタン配置がそのまま XInput系ゲームパッドで、B決定 Aキャンセルなのが辛い。

f:id:hiyokosabrey:20201009012426p:plain

ゲーム中のナビ表示に従ってきた経験で決定やキャンセルをボタンの場所だけでなく文脈(でいいのかな?)で体得しているのを改めて実感。

Nintendo Switch版 はまだリリースされてないけど XInputと逆なので、たぶん今の仕様でも問題なさそう。

f:id:hiyokosabrey:20201009013145p:plain

 

先日公開されたPS5 の仕様も考えると、マルチプラットフォームや縦マルチ対応でこの辺りを開発される現場の方々の苦労を想像するといろいろこみ上がるものを感じます。

『原神』を遊んでいて気になるのは、UIの操作ナビ表示に頼りすぎててボタンの役割をうまく設計できていないところ。細かい話になるのでこの辺はまた別の機会に譲るとして、ゲームパッドにやさしい作りになってない印象を受けてしまうんだけど、今後どこかのタイミングで対応が入るのかな。

 

 

UMGでヒット&ブローを作ってみた

作ったといってもNintendo Switchアソビ大全に収録されているゲームをUE4で再現しただけです。マスターマインドっていうかなり古いボードゲームがあったよな~となんとなく記憶の隅にあった程度で、いざ遊んでみるとこれが結構面白い。ルールはシンプル。隠された4つの色と順番を当てるだけ。CPUの思考とかもいらないし、ほぼほぼUIだけじゃん、て甘く考えてUMGで作ってみたわけです。できたのはこんなやつ。

f:id:hiyokosabrey:20201010100753j:plain

あとでブログの記事か、UIプロトタイプの教材にできないかな~と考えながら作ったので、あえて仮素材感バリバリです。

Widgetの切り分けとカーソル制御、判定部分で悩みましたが、なんとか遊べるとこまでできました。記事読みたい人いるかな?

 

このゲームは基本的にゲームパッド操作に向いていません。それをちゃんと遊べるようにしているのがさすがNintendo。そこに感心したのが今回作ろう思ったきっかけでもあります。とはいえ問題点がまったくないわけではなく、Joy-Conで遊ぶ時アナログスティック操作で動かしたくないほうのカーソルを動かしてしまい慌ててしまうこと。

 

UIの仕様はだいたい以下のとおり

 

  • 移動方向の違うカーソルが同時に2つ存在する
  • 中央縦に並んだ4つの穴すべてに、画面下の横に並んだ6つの選択肢から選んでセットする
  • 4つ埋まると判定可能になり、OKボタンが出現
  • 判定結果をテキストと4本のピンで知らせる
  • 左端から順番に判定していく
  • タップ操作も対応(今回の検証では無視)

 

で、作っていて気づいたことがあって、

一つセットすると、カーソルが次の穴に移動するかしないか。というもの。

ただ遊ぶだけだったらきっと気づけなかったと思う。

本家では自動で次の穴にカーソルが移動します。

文字入力の際にキャレットが移動するのと同じ感覚。

ところが自分で一から作っているものですから、ちょっとずつ作りながらテストします。まずは自動でカーソルが移動しない状態ができたので、遊んでみたところものすごく遊びにくいことに気づいたのです。

おそらく原因は、カーソルが2つあって独立して操作しなければいけないところ。

  f:id:hiyokosabrey:20201011102637p:plain

気持ちは次の穴に向かっているのに、カーソルは動かない。次の色も選ばなくちゃいけない。これがそこそこ気ぜわしくなって、操作の順番がおかしくなることがしょっちゅう起こりました。バグ取りしつつ何度か試すけど頭が慣れてくれない。で、ようやくインクリメント(でよかったかな?)処理を入れたら、なんということでしょう!とりあえず4つすべて埋まるまでは色を選ぶことに集中できて快適になりました。

こういうのは、デザイナーがあれこれ考えるより先に、プログラマーが先に解決してくれてたりするので、今回気づけたのが妙に嬉しかった。

 

そういえばこれに近い感じのゲームがあったのを思い出しました。

ナンプレです。数独とも呼ばれますね。あれは9x9マスの移動に方向キーを全部使うので、このヒット&ブローのような操作で混乱することはない。ナンプレも結構好きで自作したこともあるのですが、よく見かけるのがミニポップアップ方式。ヒット&ブローだとこんなイメージかな。

  f:id:hiyokosabrey:20201011104324p:plain

これだと上下移動と左右移動が同時にはできなくなるので、操作が混乱することはなくせます。ではなぜこれを採用しなかったか?

おそらく、画面下に選択リストを配置しているせい。ただしこの存在価値は非常に高いと思われるので、費用対効果を考えて残したのだと思います。推測ですが、

 

  • 画面がにぎやか(穴がいっぱいあるだけなので、このゲームの場合重要)
  • 選択肢(=出題の範囲)の数がわかる
  • アナログゲームの趣き=コンポーネント(駒とか)の手触りをイメージ
  • 操作しているより考えている時間の方が長い

 

あたりかなと。特に2番目の選択肢の幅が明確なのは、思考するときに重要な要素。

これは試してないですが、実際に作りながらだと検証できますね。

 

このカーソル送り機能は実際に試してみて気づくことができました。この感覚を共有したいのですが、文字で伝えるのは難しいです。ということで、ゲームUIデザイナーの紳士淑女の皆さんにはぜひともアンリアルエンジンでプロトタイピングを嗜んでいただきたいなと強く心に思った次第です。

 製品になったUIは、開発者の試行した結果が結晶化している状態なので、直接本人から聞き出さない限り、どうしてそうなったのか?という理由は推測するしかなく、真相は藪の中。

一から自分のUIを作れるようになるには、デザイン力と情報設計力は大事だけど、何より説得力がカギ。ロジックは問題ないようにしてやるからデザインは任せろ、と言えたらどんなにカッコいいか!とはいえ、仕様変更なんて世の常。諸行無常の響きがこだましています。どんなデコレーションにも対応できるロジックが自分の中にないと、デザイン変更に耐えるのはかなりしんどいものです。そこで体験として持っていると、UI提案する際に戦力アップ間違いなしです。

そこに遊び心が加わるともう一気にUIクオリティが上がります。

というわけでちょっと大げさに盛りましたが、実際作ってみたらこうだったという気づきは、できれば日常的に経験値上げしていきたいなと思う今日この頃。

 

 

オーバーロイドが楽しい

人に話すと大抵ラノベオーバーロードと勘違いされるのですが、アナログのカードゲームです。

OVERЯOID と書いてオーバーロイドと読みます。2人で対戦します。13枚のカードしか使いません。カードの役割を覚えるまでは、リストを作ってみながらやるといいです。

ルールは超シンプル。一枚づつ出し合って数字の大きいほうが勝つというもの。そこにカードごとの効果が加わることで、より複雑な心理戦が繰り広げられます。自分の持っていないカードを相手が持っていることにはなるので、読みやすいと思いきやそう簡単には読めないのがこのオーバーロイドの真骨頂。6枚づつ配って1枚残った伏せ札。これがまた悩ましい。とにかく確実に勝てるカードが一枚もないのです。たった13枚しかないのにこの凝縮された感じ。勝敗がついた後の感想戦もまた大変楽しく盛り上がります。数字と役割とのバランスが絶妙で、シンプルなのに同じ展開にならない奥深さ。

とてもよくできているので、気になった方は是非一度遊んでみてほしいです。

 

オンラインでした手に入らないみたいなので、すぐに試せる簡単な方法をご紹介。

トランプの A~K までの13枚を用意。

あとは、公式サイト にルールも載っています。カード効果 も載っているので、これを見ながらでも十分プレイできます。

イラストもカードのデザインも素敵で、楽しみ方がわかれば本物のカードを手に入れて遊ぶと雰囲気が出て盛り上がること間違いなしです。

 

 

バリウムがおいしく感じた

火曜に年一回のドック検診受けてきまして、珍しく空腹だったせいか、バリウムを飲んだ時に、ああ、これが食べ物だったら・・・と悲しくなるくらい美味しくいただきました。空腹感すげぇ。バリウムはお腹に溜めておくと危険と脅されるので、出し切るためにゴハンに申し訳ないと思いつつドカ食いする。今年は検査会場の近場で使える食事券をくれた。有難かったけど、このお金はどこから出ているのだろう。

 

 

UMGの最適化の話

この記事を書いているときにTwitterに流れてきたこれ

 

興味深いことを紹介してくれていてうれしい。特にSMeshWidgetのパーティクルは面白いですね。Mapのアイコンのような大量の表示パーツがある場合などに効果的って話で、ぜひ将来のVerで使えるようにしてほしい。

負荷軽減のテクニックで、Tickをなるべく使わないとか、Visibility設定の Hiddenよりは Collapse の方がいいよ とかはそれなりによく聞くやつだけど、ツリーの平坦化、階層を深くしすぎないというのと、HitTest しなくていいものは 無効にするというのは、確かに!って思った。

Widgetの生成はコスト高いので、プールして管理する方法はそれなりに考えたりします。たとえばフェードインアウト用のWidgetや汎用のダイアログなんかは、常駐させる方が何かと都合がいいし。表示頻度やタイミングなんかを相談して決める感じ。

 

 

 

 

 

今回はこの辺で

 

みなさま お体大事になさってください

ではでは

 

 

 

 

 

 

 

 

 

 

 

 

セリフの表示の速さを調節するあれのあれ《後編》

秋草の花粉かホコリかわかりませんが鼻水とくしゃみが止まりません。せっせとティッシュの山を築き上げつつ、とりあえず座っている頭の高さを越えるまでに書き上げようと思います。

前回の続きです

 

limesode.hatenablog.com

 テキストをタイプライターのように一文字ずつ表示するとこまで作りました。

セッティング用のUIを作っていきます。

 

調整に必要なパーツはなんでしょうか?

タイピング速度が設定できればいいのですがここで、どういった方法で調整したいのか考えます。

  • 数値入力は面倒
  • 直感的にやりたい
  • 細かすぎるのはやだけど、微調整したいかも

とかなんとか検討の結果、スライダーが適任かと思われます。

ただしマウスの移動量は物理的なものなので、スライダーの変化の幅を大きくすると、微調整しにくくなります。下図はちょっと極端な例ですが同じ距離を移動したときの変化量を電卓で調べてフレームアニメーションにしたものです。

f:id:hiyokosabrey:20200921223245g:plain

 

ちょっと極端な値も見てみたいかもしれない。

そこで補助機能としてスライダーの最大値を変更できるようにします。

ここは微調整しなくてもよさそうなのでスピンボックスで。

気になったらスライダーに替えればいい。

あとはテスト用に仕込んでおいた 待機時間を調整するやつ。

これもスピンボックスで。

 

 

というわけで、

さっそく新しくWidgetを作成。

f:id:hiyokosabrey:20200921220622p:plain

このWidgetはあくまでも検証用です。好みの値を試しながら、議論して最終的な値を確定させるための役割なので、確定したら不要になります。

ですので肩の力を抜いて適当に置きたいものを置いてちゃちゃっと作ります。

 

キャンバスにパーツを並べていきます。

下のようなレイアウトにしてみました。

f:id:hiyokosabrey:20200921220715p:plain

ヒエラルキーはこのようになりました。CanvasPanel以下の階層は平たんです。

f:id:hiyokosabrey:20200922000230p:plain

左側の3つのTextBlockはラベルです。右側の4つはブループリントと連動します。

まず、一番右上の TextBlock は スライダーの値を流し込むので、Is Variable を有効にします。

f:id:hiyokosabrey:20200922000418p:plain

適当に初期値を決めておきます。

f:id:hiyokosabrey:20200922000704p:plain

なんとなく 0.1 くらいでいいかと。

 

次に スライダーの設定を確認。

Appearanceの項目を編集します。

f:id:hiyokosabrey:20200922001432p:plain

Value は 初期状態の値としてなんとなく決めた 0.1  にしておきます。

Min Value(最小値)と Max Value(最大値)もなんとなく入れておきます。

最小値の 0.0167 は 60fps想定で、 1/60=0.01666666... から。

0 にすると停止します。

 

次に最大値のスピンボックス

こちらは Content の項目

f:id:hiyokosabrey:20200922003035p:plain

これもなんとなくな値を入れておきます。

ただし Value(初期値) は スライダーの Max Value と同じにしておきます。

 

次は 待機時間のスピンボックス

f:id:hiyokosabrey:20200922003403p:plain

これもなんとなくな値を入れておきます。

Value(初期値)は、テキスト表示用Widgetで変数の初期値として設定した値です。

 

UIパーツの設定ができたので、イベントを用意します。

On Value Change (*) という便利なイベントがあらかじめ用意されています。

まず スピンボックスを選択した状態で

f:id:hiyokosabrey:20200922010045p:plain

Detailタブを下の方までスクロールさせます。

f:id:hiyokosabrey:20200922010301p:plain

Events の項目にある On Value Changed の右の+ボタンをクリック。

すると 自動でグラフに切り替わります。

f:id:hiyokosabrey:20200922010538p:plain

 

このイベントにつないでいく前に必要な変数を2つ用意します。

f:id:hiyokosabrey:20200922004218p:plain

プロジェクト内に作ったWidgetは、変数の型として扱うことができます。

WB_TextType は前回の記事で作ったWidgetです。

この変数の Expose on Spawn を有効にします。

f:id:hiyokosabrey:20200922004736p:plain

 

変数が揃ったので、イベントにつないでいきます。

f:id:hiyokosabrey:20200922011231p:plain

右端は、WB_TextType型の変数を通して中に用意したカスタムイベントを呼び出して値を渡しています。

 

Float型の値をText型のピンにつなげようとすると、自動でキャスト(型変換)ノードを挟み込んでくれます。

このキャストノード、初期設定だと小数第3位で四捨五入するので、少し設定を変えます。▼をクリックしてたたまれたノードを展開します。

f:id:hiyokosabrey:20200922011850p:plain

一番下の Maximum Fractional Digits を 4 に変更。

これで、0.0167 が 0.017 にならなくなります。

 

スピンボックスも キャンバス の方 でパーツを選択しておいてから、On Value Changed の横にある 緑色の+ボタンをクリックします。

グラフはこんな感じです。

f:id:hiyokosabrey:20200922013657p:plain

最大値のスピンボックスは、値が変更されると即座にこのイベントが呼ばれ、その瞬間の値がピンから出てきます。それをすかさずスライダーの最大値にセットしています。

 

一方の待機時間のスピンボックスは、テキスト表示用Widgetに値を渡しています。

 

ちなみに緑の+ボタンは、イベントノードが作られると、View ボタンに変わります。

f:id:hiyokosabrey:20200922014052p:plain

クリックするとそのノードの場所へジャンプします。

こういった細かい気遣いがUE4の好き。

 

これでこのWidgetは完成です。

 

このセッティング用Widgetを前回表示テスト用に作ったレベルブループリントに追加します。

f:id:hiyokosabrey:20200922100620p:plain

 WB_TextType型の変数の Expose on Spawn を有効にしているので、初期値として直前のCreate Widget ノードからの ReturnValue(戻り値)を渡すことができます。

 

これで、セッティングWidgetから テキスト表示Widgetのイベントを呼び出せるようになるので、パーツは全てそろったことにはなります。

f:id:hiyokosabrey:20200922101747j:plain

 ただマウスカーソルが常時表示でないし、テキストは一つだけど永遠に次のテキストに切り替わらないので、とりあえず待機時間の仕組みを確認するための処理を追加します。

f:id:hiyokosabrey:20200922102757p:plain

テキスト表示が完了した際に通知を受け取る必要があります。そこで イベントディスパッチャー と バインド(紐づけ) しておきます。

 つながっていた GoTypingノードと入れ替えます。

f:id:hiyokosabrey:20200922103631p:plain

ここにカスタムイベントを追加

f:id:hiyokosabrey:20200922103942p:plain

白いラインが途切れて GoTypingが呼ばれなくなったので、バインドノードの後ろに追加します。

カスタムイベントを呼び出すには、My Blueprint > Graphs > EventGraph の中にあるのをドラッグ&ドロップします。

f:id:hiyokosabrey:20200922104503p:plain

f:id:hiyokosabrey:20200922104635p:plain

続けて、マウスカーソルの常時表示のために、PlayerController が持っているフラグを有効にします。

f:id:hiyokosabrey:20200922105000p:plain

GetPlayerController ノードを取り出してそこから、show で検索すると見つけやすいです。

f:id:hiyokosabrey:20200922105334p:plain

これでようやくすべてが機能するはずです。

 

 

確認してみます。

スピードの値を小さくすると残像が長く伸びるのがわかります。

f:id:hiyokosabrey:20200922110305j:plain

0.0167 の値で、 StandAloneで実行して動画キャプチャして数えてみると、おおむね 57文字表示されてました。小数点を扱うので丸め誤差もあるかもしれない。どちらにしろ速くしても目で追いかけるのは無理なので安定するほどほどのところで最小値を決めたい。この辺の値を探る目的で作ったので、作った意味はそれなりに得られたと思います。ちなみに 0.1 ではきっちり10文字表示されました。

また、テスト表示ということでほぼ負荷を気にしない作りなので、0.0167以下の値  0.001 (1ms?) だと更に高速に表示されます。

 

こんな感じのサンプルを作ることで、プロジェクトの偉い人と一緒に値を決めたり、感覚を共有できます。

 

今回のテキスト表示は、タイピング速度の検証を優先したので、テキスト表示自体はすごくシンプルで、任意改行や文字修飾に対応できていません。あとは欲しい機能に合わせてアレンジしたり工夫すると面白くなると思います。

 

おまけ

テキストをあと何種類か追加してローテーションさせてみます。

レベルブループリントにまず変数を3つ用意

f:id:hiyokosabrey:20200922144345p:plain

 

バインドノードと イベント呼び出しノードの間でマクロと変数の初期化を行います

f:id:hiyokosabrey:20200922144741p:plain

マクロの内容は以下

f:id:hiyokosabrey:20200922145017p:plain

MakeArrayノードを使って好きなだけつなぎます。

つなぐのはこのノード。

f:id:hiyokosabrey:20200922145200p:plain

順番入れ替えや差し替えがラクです。

ピンを増やすときは Add pin + をクリック。いらないピンは、そのピンの上で右クリックして Remove array element pin を選択すると削除できます。

 

お気に入りのキャラを表示して、いい感じのセリフをしゃべらせると楽しさがアップします!たぶん!

 

 

マクロができたら、仕上げにテキストの順番を進める部分を作ります。

f:id:hiyokosabrey:20200922145843p:plain

マクロ内で、テキストの最大数を調べてあるので、その数で剰余を計算すると最大数までの範囲でループするような結果になります。剰余はほんとに便利なので当ブログでもよく登場します。ブループリントだと 「%」 マテリアルだと 「fmod」 です。

テキストを表示するたびにカウンタである TextIndex 変数を1加算しているので、次回表示する際は新しいテキストになっていて、最大数までカウントするとまたゼロに戻って・・・というのを繰り返します。ブランチノードで判定するよりシンプルです。

 

動画を撮ろうかと思ったのですが、ものすごく地味な動画になりそうなので、保留にします。そんなにややこしい構成ではないと思うので、興味が沸いた方はぜひ試してみてください。リクエストがあれば・・・考えます。

 

今回は以上です。

メッセージ表示のUIって、いざ作ってみるといろいろ工夫できて面白いですね。いい感じにできると、あとはシナリオとキャラがあればゲームができそうな気さえします。

なんとかティッシュに埋もれる前に書ききることができました。

鼻がひりひりします。

分かりにくいとことか、あれれ~おっかしいぞー?みたいなとこあれば容赦なくツッコミお願いします。

最後にちょっと前にCEDECの講演で話題になったキーワードについて、自分の思っていることをしゃべらせてみたのを貼っておきます。

f:id:hiyokosabrey:20200922180325j:plain

f:id:hiyokosabrey:20200922180345j:plain

 

ではでは

ステキな テキスト表示ライフを!

セリフの表示の速さを調節するあれのあれ《前編》

PS5の予約が始まりましたね。初代機が発売されて四半世紀が経過。あの四角形のポリゴンを傾けたときのテクスチャの歪みに抗おうとしてた頃が懐かしいです。

ふと当時が思い出されたので、Photoshopでドットを描いて再現してみました。

 

f:id:hiyokosabrey:20200919010108p:plain



今はもう、少ないパレットカラーでレンガを作ることもないのですね。

 

 

 さて、しみじみしたところで、今回は、ツール的なものをネタに書いていきます。

 ジャンル的にADVでいいのかな。大昔のPCゲームでアドベンチャーゲームといえば、アドベンチャーな世界で、アドベンチャーなストーリー展開でまさにアドベンチャーしていたとかすかに記憶していますが、ヴィジュアルノベルとかノベルゲームの方がアドベンチャーゲームの系譜に近い気がする。実は世間ではすでにアドベンチャーゲームってなんだよ、意味わかんねーよw、と言われているような気がしないでもない。そんなADVゲーム的なゲームで必ずといっていいほど見かけるのが セリフ枠 とか メッセージ枠 とか呼ばれるやつ。「枠」は「ウィンドウ」に置き換えて メッセージウィンドウ という呼び方もします。メインのゲームがADVじゃなくても途中で挿入される会話劇なんかで今でもよく見かけます。

 美しい立ち絵を眺めながら小芝居と会話劇を堪能するためのセリフ表示システムとしての役割で扱われている印象が強いゲームのテキスト表示とその周辺のUI。

 位置固定式フキダシ表示システム とでも言いましょうか。Googleの画像検索でスクショを眺めてみると、タイトルを印象付けるユニークなデザインになっている様子がうかがえます。UIデザイナーとしては頑張り甲斐のあるところですね。

 ゲームプレイ全体で目にする時間も長いので、デザインも凝ったものが多く、またいろんな機能がついていたりします。中でも当たり前にあるのが表示速度調整。コンフィグとかの設定をみると、ゆっくり~はやい などでだいたい3,4段階というところでしょうか。

 調整機能を入れつつも、タイピング中にボタンを押すと最後まで一気に表示する仕組みも今では普通に実装されていて、さらに連打やうっかり押しちゃってさっきのセリフなんだっけ?となったときのために会話ログが閲覧できるようになっていたりと、UI的にもかなりの進化を遂げていると思います。

 

 だいぶ前置きが長くなりましたが、今回作ったのはこの調整機能を実装するために段階を確定するための検証用の仕組みになります。ややこしい。

 つまり開発用です。プロトタイプとしてサクッと作ってみました。

f:id:hiyokosabrey:20200919153758j:plain

 

ではさっそくベースになるセリフ表示のパーツから

 

 

まずはタイプに使う文字。

キータイプっぽい見せ方をしたかったのでカーソルの残像が残るようなアニメーションから作っていきます。

 

新しいWidgetをアセットブラウザ上で作成。

f:id:hiyokosabrey:20200919162514p:plain

ダブルクリックして開いたら、

キャンバスに 新しく CanvasPanel を置きます。

f:id:hiyokosabrey:20200919162219p:plain

キャンバスの方にドロップしてもいいのですが、ポジションをリセットするのが面倒なので、ポジションを調整しない場合はヒエラルキーパネルの方にドロップすると楽ちんです。

 

置いたら、 Size To Content を有効にします。

f:id:hiyokosabrey:20200919154808p:plain

 

続けて

CanvasPanelの中に TextBlock をひとつ追加して、

f:id:hiyokosabrey:20200919162905p:plain

書体と文字のサイズを決めたら、これも Size To Content を有効にしておきます。

f:id:hiyokosabrey:20200919154606p:plain

これで、文字の大きさによってキャンバスパネルが可変してくれるようになります。

f:id:hiyokosabrey:20200919155427g:plain

さらに Is Variable も有効にします。

f:id:hiyokosabrey:20200919172605p:plain

これを有効にすると、ブループリントから触れるようになります。

 

TextBlockの上に Image を被せます。

f:id:hiyokosabrey:20200919162920p:plain

 

Imageのアンカーは右下のやつ。

f:id:hiyokosabrey:20200919155819p:plain

Offsetはすべて ゼロ

f:id:hiyokosabrey:20200919160123p:plain

これでCanvasPanelの大きさに追随してくれます。

f:id:hiyokosabrey:20200919155644p:plain

結果的に 文字の大きさに合わせて Image のサイズも変化することになります。

 

3つのパーツを追加しました。ヒエラルキーは以下のようになります。

f:id:hiyokosabrey:20200919160404p:plain

 

次はアニメーション。

f:id:hiyokosabrey:20200919160709g:plain

Image が透明になって消えるだけです。 ループはしません。

キャンバスの編集はこれで終わり。
ブループリントを編集していきます。

 

文字を受け取るために、Text型の変数を一つ追加。

記号なども含めて「文字」のことを英語でキャラクターというので、Character から4文字いただきました。

f:id:hiyokosabrey:20200919163248p:plain

Expose on SpawnInstance Editable を有効にしておきます。

このWidgetが生成される際に、同時に値を受け取ることができます。

 

Event Construct にノードをつないでいきます。

f:id:hiyokosabrey:20200919165743p:plain

Delay ノードは必要というわけではないので無くても大丈夫。

雰囲気的に調整する目的で置いてますが、0 を入れるとスルーします。

この待ち時間が必要と決まれば、アニメーションの方を編集して尺を伸ばし、このDelayノードは削除しましょう。

 

これでWidgetが一つ完成です。wb_char と命名

f:id:hiyokosabrey:20200919171606p:plain

このWidgetアセットを アセットブラウザ上で複製します。

f:id:hiyokosabrey:20200919171756p:plain

 

名前は 待機用ということで wb_wait にします。

f:id:hiyokosabrey:20200919171933p:plain

中身をいじっていきます。

 

キャンバスの TextBlock を 見えなくします。

f:id:hiyokosabrey:20200919172214p:plain

アニメーションも削除します。

 

 

次にブループリント。

Event Construct につなっがているノードをごっそり消します。

f:id:hiyokosabrey:20200919173100p:plain

Text型の変数 Char も不要なので削除します。

 

スッキリしたところで、カスタムイベントを追加。

点滅する処理を作ります。

ループアニメーションを使うと、ノードはシンプルになりますが、ただ点滅させるだけなのでタイマーを使います。

f:id:hiyokosabrey:20200919173847p:plain

Set Timer by Event ノードの 赤いラインは、ちょっと変わっていて イベントとつなぐために使います。つないだイベントを呼び出すことができるのです。なので、この場合時間が来たら再び先頭のイベントが呼ばれるのでまた自身に処理がやってきます。いわゆるループです。

FlipFlopノードは、処理が来るたびに、出口がAとB交互に切り替わるので結果的に点滅することになります。

Set Timer by Event ノードが呼ばれなくなったら実質ループ終了ということになりますが上の場合特に何も条件を付けていないので、放っておくと無限にループしてしまいます。さすがに無限ループはご法度なので、しっかり止める仕組みを入れます。それがタイマーハンドラー。

 

タイマーハンドラーは、Set Timer by Event ノードの Return Value ピンから作ります。

f:id:hiyokosabrey:20200919174444g:plain

ドラッグしてPromote to Variable を選択すると、変数が作られます。

これはタイマーイベントをハンドリング(制御)するために用意する変数で、タイマーがセットされて定刻になるまでに中止するときや、一時的にポーズするときなどに使います。

今回は、このWidgetが消されるときに、タイマーを止める処理で使います。

 

最初から用意されているイベント  Event Destruct ノード を取り出して、タイマーを止める Clear and Invalidate Timer by Handle ノードをつなぎます。

f:id:hiyokosabrey:20200919175324p:plain

仕上げに、点滅用のカスタムイベントを Event Construct につないで2つ目のWidget完成。

f:id:hiyokosabrey:20200919180345p:plain

 

 

 

そして3つ目のWidget

ゲーム画面ぽいやつ

f:id:hiyokosabrey:20200919215109p:plain

キャンバスにそれっぽいのをレイアウトします。

f:id:hiyokosabrey:20200919215806p:plain

必要なパーツは WrapBox

これは子供の要素を左上詰めで並べていって、決めておいた幅を越えるのがわかると、改行してくれるパネルです。ガンガン Add Childs しても右に はみ出すことはありません。

f:id:hiyokosabrey:20200919220015p:plain

ここにテキストを流し込むので、それ以外は自由なデザインで。

 

キャンバスがいい感じになったら、グラフの編集。

 

変数を4タイプ6つ新しく用意します。

f:id:hiyokosabrey:20200920222645p:plain

 

文字をタイプしていくための カスタムイベントを用意します。

f:id:hiyokosabrey:20200920225952p:plain

ブループリントから動的にオブジェクトを生成する Construct Object from Class ノードに、

f:id:hiyokosabrey:20200921101334p:plain

 

文字表示用に作っておいた wb_char をセットすると、

f:id:hiyokosabrey:20200921102040p:plain

Expose on Spawn した変数が入力ピンとして自動的に出てきます。

f:id:hiyokosabrey:20200921101556p:plain

Outerピンにはそのままだとコンパイルエラーになるので、 Self ノードをつないでおきます。

この生成された結果が、WrapBoxの子供として追加されるようにしています。

このイベントが呼び出されるたびに、一文字追加というイベントになります。

 

その文字を一文字を抽出しているのが Midノード。

Text型はあまりいじることができないのでString型の状態で扱います。

Stringを操作するノードがたくさんある中に Mid  と GetSubstring が用意されています。

ヒストリアさんがきれいにまとめてくださってます。

historia.co.jp

JavaScriptだと charAt() に相当するやつを探してみたけど用意されていないっぽいですね。

 

で、続き

f:id:hiyokosabrey:20200921105613p:plain

ここでも Set Timer by Event が出てきました。タイマーハンドラーもここで作っています。

 

最後までテキストを表示し終わったら、次のテキストへの待機表現が必要です。

f:id:hiyokosabrey:20200921111350p:plain

右端は イベントディスパッチャー を Call しています。

作り方は、My Blueprintタブの一番下

f:id:hiyokosabrey:20200921111857p:plain

特別なことはしないので、名前だけわかりやすくしておけばいいと思います。

取り出すときにポップアップが出るので Call を選択。

f:id:hiyokosabrey:20200921112101p:plain

 

 

全体のノードはこんな状態。

f:id:hiyokosabrey:20200921111532p:plain

 

次に

テキストを受け取る関数を用意します。

f:id:hiyokosabrey:20200921120323p:plain

タイピング中にこの関数が呼ばれることは無いと思いたいけど、isTypingフラグを用意したので、念のためにブランチノードで判定。このフラグは今回はこれくらいの役割しかないけど、タイピングを途中でスキップする時に使えると思います。

WrapBoxはリセットしないと、どんどん追加されてしまうので、このタイミングでクリアにします。

今回見やすくするためにマクロにしました。

f:id:hiyokosabrey:20200921121135p:plain

 

あとちょっと

最後の仕上げに、カスタムイベントを2つ用意します。

f:id:hiyokosabrey:20200921122035p:plain

外から書き込まれるイベントです。受け取った値を変数に入れるだけです。

 

これでメインのテキスト表示システムは完成。

長くなったので、残りは《後編》に持ち越すことにします。

が一応テストしておきましょう。

 

適当なレベルを作ってWidgetを表示してみます。

Fileメニューから New Level を選択。

f:id:hiyokosabrey:20200921125151p:plain

レベルブループリントの編集は ↓ ここから

f:id:hiyokosabrey:20200921125457p:plain

f:id:hiyokosabrey:20200921130622p:plain



実行の前に wb_TextType で用意した変数の初期値を確認。

f:id:hiyokosabrey:20200919215109p:plain

 ClassDefaultをクリックすると編集がラクチンです。

f:id:hiyokosabrey:20200921131255p:plain

f:id:hiyokosabrey:20200921131642p:plain

 

これで準備完了。

さっそく表示テストしましょう。

f:id:hiyokosabrey:20200921135250j:plain

f:id:hiyokosabrey:20200921135300j:plainファイルサイズが大きすぎて全画面の動画は上げられなかったので、部分だけGIFにしました。

f:id:hiyokosabrey:20200921140152g:plain

森見登美彦著『有頂天家族』(幻冬舎文庫) 淀川教授のセリフから引用


今回はこの辺で

次回《後編》で調整用のUIを実装します お楽しみに~

 

 




 

キャラをキャプチャして立ち絵にしたい

今回は、キャラ絵としていい感じに抜くためのテクニックを紹介。 

UE4には高解像度でキャプチャするツールがあります。

キャプチャツールの使い方は公式に上がってるので、詳しい機能についてはそちらをご覧いただければと思います。

 

docs.unrealengine.com

 

 タイトルは明かせないのですが過去にとても大量のキャプチャで四苦八苦したときのノウハウになります。

 

撮影用のレベルを作っておくと便利です。

ライトとカメラ、キャラの3つのポジションを決めておけば、キャラ修正やポーズ変更の時、以前に撮った絵との差し替えがスムーズにできます。

f:id:hiyokosabrey:20200914224202j:plain

 

 

まず抜きたいキャラに対して、Custom Depth への書き込みを設定します。

Render CustomDepth Pass を有効にします。

f:id:hiyokosabrey:20200912231312p:plain

これを設定すると背景を抜くことができます。

F8キーを押してビューポート左上の▼ボタンから、

高解像度スクリーンショット を選択します

f:id:hiyokosabrey:20200912230812p:plain

 

 

f:id:hiyokosabrey:20200912231559p:plain

チェックボックスがいくつか並んでいます。

一番下にある マスクとしてカスタム深度を使用 を有効にします。

 

f:id:hiyokosabrey:20200912232151p:plain

CustomDepthを有効にした状態でキャプチャすると、PNG形式で書き出されて、Photoshopだと緑の部分は抜きになっていますが・・・

f:id:hiyokosabrey:20200912232507p:plain

実際には緑はしっかり残っていて、透明で見えないだけなのです。Photoshopでは確認の術がありません。

このPNGをそのままUE4でインポートすると・・・

f:id:hiyokosabrey:20200912233634p:plain

しっかりエッジに侵食しているのが分かります。

なので、キャプチャする際はCustomDepthを有効にしたやつと無効にしたやつの2枚をキャプチャするのをオススメします。

 

キャプチャする前に、撮影用のカメラを切り替えないといけませんね。

F8でゲームを一時的に抜け出すと専用のカメラに切り替わりるので、キャプチャ用のカメラに乗り換えます。

念のためカメラのトランスフォームをロックしておくことをオススメします。

f:id:hiyokosabrey:20200912235319p:plain

再びワールドアウトライナから同じ撮影用のカメラを選んで右クリックして Transform > Lock Actor Movement を選択するとロックできます。

 

この流れでもう一度撮影用のカメラで右クリック、今度は飛行機のアイコンがついた Pilot~ を選択します。

f:id:hiyokosabrey:20200912235551p:plain

これでカメラが切り替わります。

 

ようやく撮影できます。

f:id:hiyokosabrey:20200913000240p:plain

倍率はディスプレイに描画しているサイズに対しての倍率になるので要注意です。

エディタのビューポートが小さいと小さくキャプチャされます。少しでも大きくしたい場合は F11 キーを押して全画面(Immersive Mode)にしてからにしましょう。

倍率は、大きくするとポスターなんかでも耐えられる大きさを撮れますが、使っているグラボの限界を超えるとエンジンがクラッシュします。慎重にほどほどに。

 ちなみに RTX2060 を使っていますが、 1920x1080 を 7.0倍にしてキャプチャするとクラッシュしました。

f:id:hiyokosabrey:20200913144647p:plain

 

6倍だと 11520x6480px にもなります。250~300dpi で 横幅がおよそ1mほど。

A0のポスターサイズです。

f:id:hiyokosabrey:20200913152032j:plain

比較するために 1.0~6.0 の倍率で撮った画像から、一部分を同じ大きさで切り抜いてみました。

f:id:hiyokosabrey:20200913151850p:plain

 

6倍のやつは、PNG圧縮された状態で 22MBありました。

 

 で、いざキャプチャ!

f:id:hiyokosabrey:20200913163725j:plain

マスクとしてカスタム深度を使用 を するVer と しないVer の2枚を撮ります。

f:id:hiyokosabrey:20200913163735j:plain

この2枚をPhotoshopで開きます。

 

Photoshopの隠れた? テクニックを使います。

同じサイズのドキュメント間でのみ使えるテクニックです。

抜きになっている方を、抜きになってない方に移動して、

Ctrl + Alt + Shift キーを押しながらドロップ

f:id:hiyokosabrey:20200914213037p:plain

これでぴったり同じ位置に重なります。

f:id:hiyokosabrey:20200914213105p:plain

 

次にアルファチャンネルを作ります。

2つほど方法があるのですが、簡単な方で書きます。

後から重ねた方の、抜きになっているレイヤーのサムネイルを、 Ctrl キーを押しながらクリックするとピクセルの存在する部分を選択範囲として取ることができます。

f:id:hiyokosabrey:20200914214004p:plain

その状態のまま、

チャンネルパレットにあるボタンから選択範囲を保存します。

f:id:hiyokosabrey:20200914215040g:plain

新しくアルファチャンネルができます。

f:id:hiyokosabrey:20200914215158p:plain

アルファチャンネルが無事できれば、抜きのレイヤーは不要なので削除できます。

あとは、テクスチャに合うようにトリミングして完成です。

サイズ調整する場合は、スマートオブジェクトにすると非破壊で差し替えがラクです。

 

フォーマットがどうしてもPNGじゃなきゃ死んじゃう!でなければ Targa形式(*.tga)での保存をオススメします。

 

エンジンにインポートして確認。

緑のフチドリは出ていません。

f:id:hiyokosabrey:20200914221559p:plain

完成!

 

 

ここからはおまけ

 

このキャプチャにはブルームが入っていたりします。

f:id:hiyokosabrey:20200914231052p:plain

ブルームの有り無しで絵の華やかさが変わったりするので、基本有効にしておきたいところですが、輪郭の部分はアルファで容赦なくバッサリ切られます。

また、Sci-Fi系や魔術系のキャラなどの発光パーツでは必須です。ビームサーベルとかw

ポストプロセスで描かれているので、カスタム深度とは無縁なのです。

 

そこでマテリアルを使って再現します。

使うテクスチャは別に用意したりせずそのまま使えますが、少し地味なので、Photoshopで盛ることにします。

アルファを作ってトリミングしたテクスチャにブラシでブルームを足してやります。

f:id:hiyokosabrey:20200914235036p:plain

ちょっとはエモくなったかな?

 

まず、このブルーム用のマテリアルを用意します。

f:id:hiyokosabrey:20200914232214p:plain

汎用のマスターマテリアルとして使うので、テクスチャはTextureSampleParameter2Dです。

マテリアルドメイン(右端の茶色いノード)の設定を Additive(加算)に設定します。

f:id:hiyokosabrey:20200914232520p:plain

あとはこのマテリアルからインスタンスを量産して、そこにキャラごとのテクスチャをセットして運用します。

マテリアルインスタンスは、アセットブラウザのマテリアルアセットアイコンの上で右クリックすると一番上に出てきます。

f:id:hiyokosabrey:20200914232828p:plain

 

アセットブラウザに並んだ状態 (名前は適当)

f:id:hiyokosabrey:20200914233049p:plain

 

これをUMGでレイアウトします。

まずImageを一枚レイアウトしたら、マテリアルインスタンスの方をセット。

f:id:hiyokosabrey:20200914235348p:plain
加算なので、グリッドが透けているのがわかります。

ここにもう一枚同じ大きさのImageを手前に重ねておきます。同じポジションです。

複製(Ctrl+W)すると速いです。

こちらにはキャラ絵のテクスチャをそのまま貼ります。

f:id:hiyokosabrey:20200914235407p:plain

ブルームマシマシ再現完了です。

 

適当なレベルで表示してみると、

f:id:hiyokosabrey:20200914235711j:plain

おお、まぶしい!

 

キャプチャした時に床が入り込んでたので、下の方が白くなってます。このようなブルーム再現で使う場合は、カメラに入らないようにするか、Photoshopでレタッチして完全な黒にしておくといいです。

 

昔はHIGHモデルを表示するのはコストがかかったもんです。テクスチャ容量に頂点数、モーションに、ライティング、さらに口パク。画面に大きく出るので細かいとこまで作りこまないと安っぽさが目立ってしまいます。制作コストもかかるし、ロード時間の問題もあって、キャプチャして 2D で表示するのは、それなりに旨味がありました。

最近はサクサクロードできて、モーションもいい感じに再生できる時代なので、今回のテクニックは、パブ系の素材か、ゲームだとインベントリ内に表示するアイテムのグラフィックぐらいでしょうか。

ちょっと枯れた感じがしなくもないですが、誰かのお役に立てれば幸いです。

 

ではでは

今回はこの辺で

ステキはキャプチャライフを!