みつまめ杏仁

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

スライダーUIを並べて操作してみる

 

f:id:hiyokosabrey:20180210235447p:plain

前回 キーリピート処理を試すために作ったUIパーツのスライダーを並べてそれっぽく操作できるようにしてみようというのが今回の記事です。

 

limesode.hatenablog.com

 

まずは スライダーのWIdgetにパーツとアニメーションを追加します。追加するパーツは3つ。

項目名を示す「ラベル」と、「左右のキーを入力してね」と「いまこの項目を触ってるよ」という意味を持たせる一組の  <  > になります。

f:id:hiyokosabrey:20180211000308p:plain

f:id:hiyokosabrey:20180211000331p:plain

ラベル用のテキストブロックは、ブループリントから内容を書き換えるので、

Is Variableにチェックを付けます。あとの< > はブループリントからは直接触らないので画像等にしてもOK。

アニメーションは全部で4種類。

  • FOCUS ・・・ フォーカスされたとき
  • UNFOCUS ・・・ フォーカスが外れたとき
  • RIGHT ・・・ →右キー を入力したとき
  • LEFT ・・・ ←左キー を入力したとき

f:id:hiyokosabrey:20180211084832g:plain

左右のキーを入力したときのアニメーションは、ツマミが動くので、必ず必要ということはないですが、キー入力に対するリアクションは、分かりやすいほどユーザーフレンドリーなUIとなります。また、ユーザーは操作しながら無意識的にこのリアクションを記憶して学習していくので、「< > を見かけたら 左右入力できそう」というUI操作に対する期待感を育てることができます。これもひとつのUXです。デザインの段階で記号化のルール作りはとても重要になります。ここ試験に出ますよ(何のだ?)

 

Widgetブループリント

初期状態の値をもらう関数にラベルをセットする処理を追加します。

f:id:hiyokosabrey:20180211090404p:plain

Text型の引数(Inputsピン)を追加します。最後にスライダーの値更新用の関数をつないでいます。これは前回作ったやつで、処理の順番でおこる不具合対策でここに移動してきました。

というわけで、EventGraphが変わります。

前回↓のようになってたのを・・・

f:id:hiyokosabrey:20180211091022j:plain

こうします。

f:id:hiyokosabrey:20180211091436p:plain

ついでに左右キーを押したときに呼ばれるイベントなので、アニメーションの再生もここで行います。

 

続いてフォーカスとアンフォーカスのアニメーションを再生するイベントを新たに用意します。ただアニメーションをイベントとして再生するだけなのでカスタムイベントにつなぎます。

f:id:hiyokosabrey:20180211094506p:plain

f:id:hiyokosabrey:20180211094555p:plain

この2つの違いは、アニメーションの作り方によるものです。

UMGのアニメーションは、基本的にタイムラインの最後まできちんと再生しようとします。しかも同じ要素でのアニメーションがバッティングするとあとから再生したもので上書きされます。最終的に尺の長いアニメーションが勝ちます。

今回の4つのアニメーションでは、左右キー入力したときの LEFT と RIGHTのみ 0.2秒の尺で作りました。フォーカス切り替えでは、0.0 にキーを打っただけです。4つともカラーアニメーションです。

なので、左右キーを押して ”LEFT” か ”RIGHT” のアニメーションしている途中(0.2秒までの間)でフォーカスを切り替えると、一瞬だけ ”UNFOCUS” が再生されて残りの ”LEFT” か ”RIGHT” のアニメーションが再生されます。結果、”UNFOCUS” のアニメーションは敗北することになります。今のところ解決策は2つが考えられます。

  • 動いているであろうアニメーションを止める
  • アニメーションの要素がバッティングしないようにする

この挙動はバグにも思えますが、利用できる場面があるので、修正されないことを願っています。しくみが分かればきちんと対策できるので。(修正されるといろいろ面倒な処理が必要になる・・・)

このあたりの仕様を踏まえて、必要に応じてStopAnimationノードをつなぎます。

これでスライダーは完成です。次に並べて制御するためのWidgetアセットを新しく用意します。

 

 

 制御用Widget

f:id:hiyokosabrey:20180211105950p:plain

スライダーが一番マッチするサウンド設定の想定です。

キャンバスにバージョンアップしたスライダーWidgetを並べます。

f:id:hiyokosabrey:20180211104936p:plain

 

ブループリント

まずは準備する関数 "initSlders" を用意します。

f:id:hiyokosabrey:20180211105812p:plain

この関数を、EventPreConstructionにつないでコンパイルしてみると、

f:id:hiyokosabrey:20180211110258p:plain

キャンバスの内容が書き換わるのが確認できます。

 

引き続き関数を編集します。変数を2つ用意したいのでスライダーのWidgetノードから、Promote to Variable を2回します。

f:id:hiyokosabrey:20180211111307p:plain

作ったらすぐに消します。Variables のリストには残るので、リネームして一つは配列化します。

f:id:hiyokosabrey:20180211111803p:plain

この配列の方を関数に Set で戻します。そこに Make Array ノードをつないで、キャンバスに並べたWidgetを登録します。

f:id:hiyokosabrey:20180211112047p:plain

 仕上げに int型の戻り値(Outputsピン)に配列の登録した数をつないでこの関数は完成。

 

f:id:hiyokosabrey:20180211112722p:plain

 

 次に、int型の変数を2つ用意します。

配列に登録した3つのスライダーWidgetは、0~2の番号を使って扱うためと、スライダーの個数を保持しておくための変数です。

f:id:hiyokosabrey:20180211134356p:plain

先の関数からの戻り値を受け取るような形でつなぎます。

f:id:hiyokosabrey:20180211144806p:plain

 この続きには操作するスライダーWidgetを切り替える関数 "changeActiveWidget" を作って、

f:id:hiyokosabrey:20180211145409p:plain

くっつけます。

f:id:hiyokosabrey:20180211145615p:plain

 

あとは、前回のキーリピート処理を、レベルブループリントから持ってきます。

変数は移植できないので、ちょっと面倒ですが再び同じようにfloat型、TimerHandle型、Boolean型の変数をそれぞれ1つずつ用意しつつ、

f:id:hiyokosabrey:20180211150917p:plain

カスタムイベント "onKeyPress" を置いてつないでいきます。

f:id:hiyokosabrey:20180211151224p:plain

TimerHandle型は、Set Timer by Event のReturn Valueピンから Promote to Variable してもOK。

DoOnceノードのResetピンにつないでいた部分は、新たにカスタムイベントをつなぎます。

f:id:hiyokosabrey:20180211152032p:plain

 

前回のキー入力部分は、

f:id:hiyokosabrey:20180211152644j:plain

コンパクトにします。

f:id:hiyokosabrey:20180211152747p:plain

そして最後に、上下に並んだスライダーのフォーカスを順次切り替えるイベントを用意します。

f:id:hiyokosabrey:20180211153437p:plain

 上の2つのイベントは、←→左右キー用と、↑↓上下キー用になります。

それぞれの処理は上下と、左右で内容がほぼ同じなので、trueかfalseか、プラスかマイナスか、で分岐するようにして使い回せる形にしました。

このWidgetは一応完成です。

 

 

レベルブループリント

前回のレベルを改造するのであれば、Add to ViewportしていたWidgetが変わるので、前回 Promote to Variable していた変数が使い物にならなくなります。

f:id:hiyokosabrey:20180211154413p:plain

Input ノードで、↑ ↓ ← → のキー入力を検出して、それぞれのイベントを呼び出します。

f:id:hiyokosabrey:20180211154902p:plain

これで完成です。

再生して確認してみます。

f:id:hiyokosabrey:20180211155814g:plain

うまくいきました。

 

今回はこの辺で。それなりの操作ができるとこまでは来たかなと思います。

次回もうちょっとだけ手を入れます。

 

ではでは ステキなスライダーUIライフを!

 

キーリピート機能をつくってみる

 パソコンでキータイプしていると気づくこともあると思いますが、カーソルキーとか同じキーを押しっぱなしにしたときに、1文字目と2文字目の間にちょっとだけ間があります。タン、タタタタタタ・・・・・・ 初めてパソコンを触ったとき、当時子供だった私はモヤモヤした経験を覚えています。UIを意識するようになってようやく腑に落ちたものです。

f:id:hiyokosabrey:20180204094046g:plain

 ゲームでも、音量調節のスライダーなんかにごく当たりまえに実装されているので、身近なやつを見れば・・・って、最近はタッチデバイスなのであまり身近じゃないですね。でもまだPS4とかゲームパッドで遊ぶUIはあるので、今回ブループリントで作ってみました。

 

UMG

キーリピートの挙動を見るために、シンプルなボリュームスライダーを用意します。

キャンバスに3つのパーツを配置します。

f:id:hiyokosabrey:20180203125755p:plain

f:id:hiyokosabrey:20180203125802p:plain

右端がMAX想定なので、ツマミは左端に置きます。

 

ブループリントから触るので3つとも Is Variable にチェックを付けます。

f:id:hiyokosabrey:20180203130034p:plain

触るといっても、Image_Baseだけはサイズを取得するだけです。

 

 

Widgetブループリント

変数を2つ用意します。

f:id:hiyokosabrey:20180203130610p:plain

 

まずは、スライダーの移動範囲を調べて変数に入れます。

f:id:hiyokosabrey:20180203131734p:plain

すでにキャンバスに置いているパーツの長さを調べるので、Event Pre Constructで問題ないです。Get Size で調べたImage_Base(ラインみたいなやつ)の長さを変数 MaxPos に Set します。これは、後からデザインやレイアウトが変更になっても、キャンバスを調整するだけ(Blueprintは無傷)で済むのでオススメです。ひと手間かかってますが、こういったつくりは後で地味に効いてきます。

 

次に関数を2つ用意します。

まず一つ目は指定した値の場所にツマミを移動して、値を表示する関数になります。

f:id:hiyokosabrey:20180203132503p:plain

便利な Lerpノードを使います。AとB2つの値を線形補間したうえで、Alphaの値に応じた途中の値を返してくれるノードで、MaxPos を Bのピンにつなぐことで、どんな長さのスライダーでも対応できるようになります。MaxPosはパーツの長さを調べてるのでデザインが変更されても、勝手にこのBの値が変わっていることになります。

 

 もう一つは初期状態の値をもらう関数です。

f:id:hiyokosabrey:20180203193152p:plain

 ゲームでは設定した値をセーブしているのが普通なので、まずは初期値を受け取れるように関数で用意します。この int型の Value という変数は、念のため Private にチェックをつけておくと安全です。

 

関数が用意できたら、今度はマクロを用意します。

受け取った値を Valueに加算して、0~100の範囲を越えないようにします。

f:id:hiyokosabrey:20180203193901p:plain

越えたらループするようにしています。

減っていくとき、3 → 2 → 1 → 0 → 100・・・

増えていくとき、98 → 99 → 100 → 0・・・

このWidget以外から呼ばれる処理ではないので関数ではなくマクロにしました。

 

仕上げにイベントを用意していきます。

カスタムイベントを2つ置いてマクロと関数をつなぎます。

f:id:hiyokosabrey:20180203194836p:plain

引き算のノードを使わなくても、マイナスの値は、足し算することで引き算と同じ結果になります。汎用性の高いマクロや関数を作るときに応用できます。

 

Widgetは完成です。

次は動かすためにレベルブループリントを編集します。

 

 

レベル

おなじみのやりかたでWidgetをViewportに追加すると、表示された瞬間EventConstructが動くので、先に初期値を渡しておきます。

f:id:hiyokosabrey:20180203195847p:plain

試しに再生してみると、

f:id:hiyokosabrey:20180203200040p:plain

ちゃんと反映されていればOK。

 

 

では、キーリピートの処理を作ります。

必要な変数を用意します。

f:id:hiyokosabrey:20180203225924p:plain

まず、float型の変数は、キーリピートの間隔を保持します。スライダーが増えるか減るかをフラグで管理するためにBoolean型の変数を。一番上の RepeatTimerHNDLという名前の変数はTimerHandle型の変数で、Set TImer Event ノードの戻り値 Return Value ピンからPromote to Variable すると簡単に作れます。

 

カスタムイベントを用意して、下のようにつなぎます。

f:id:hiyokosabrey:20180203230620p:plain

右端のノードは、Widgetに作っておいた関数を呼び出しています。増えても減っても基本的なキーリピート処理は変わらないので、極力使い回せるものは使い回すようにしています。

続きはこのようになっています。

f:id:hiyokosabrey:20180203231752p:plain

 DoOnce ノードでキー入力初っ端だけ通すようにして、2回目以降のリピート間隔を float型の変数にセットしています。

 

まだ続きます。DoOnceはリセットすることができるので、キー入力をやめたらリセットするようにつなぎます。下図はカーソルキーの左右を押した場合です。

f:id:hiyokosabrey:20180203232534p:plain

 

これで完成です。

さっそく 動かしてみましょう。

f:id:hiyokosabrey:20180204084434g:plain

キー入力を開始して、ひと呼吸置く感じで動きます。

 

基本的な仕組みはイベントの自己呼び出し。 f:id:hiyokosabrey:20180204085027p:plain

あとは、DoOnceノードで、RepeatInterval 変数の値を 0.75 から 0.025 に変えます。

これでキー入力後の《 間 》が作れたことになります。この値は 1.0  が1秒です 。フレームレートによりますが 60fpsだと、0.0167 くらいで 1フレーム分です。これを変えてみるといい感じに調整できますよ。

 

この《 間 》が無いとどうなるか、0.75 をセットしてるとこを 0.025 にしてみると答えが分かります。

 

次回は、せっかく作ったスライダーをいくつか並べて操作できるようにしてみようと思います。

 

ではでは

ステキな キーリピート ライフを!

 

UIデザインというお仕事

 気がつけば2018年の12分の1が終わってちょっと焦り気味な今日この頃。残り少ない平成時代を精一杯堪能したいと思うんだけど、何をすればいいか思いつきません。あ、平成30年発行の硬貨を記念に取っておくとか?

それはさておき

2018年最初の記事は雑記で始めてみたいと思います。画像もなんもなく文字だらけなうえにテクニックとか有益な情報はないので悪しからず・・・

とりあえず、UIデザインというお仕事について、私なりに感じている事を書いていきます。

 

自分のこと

 私がゲームのUIを作る仕事に携わってかれこれ四半世紀。UIという言葉がまだなかったころから活動しております。最初は専門職という認識は誰にもどこにもなく、新人や比較的手の空いたメンバーが担当するのがUIだった時代です。

 最近では専門職としてブイブイ言わしてもらえ・・・てはいないですが、一応専門職ということになっております。今までにいろんなUIを作ってきました。「作った」と言っても一人で作れるわけはなく、私はデザイナーなので実際はプログラマとの共同作業です。

 アーケードゲームの開発から始まって家庭用のコンソール機用ゲームと多くのタイトル開発に携わっていろんなことを学びました。 今やアーケードゲームはほとんどが音ゲーや特殊な大型筐体ばかりになってしまいましたが、このアーケードゲームにおいてのUI開発はとても多くの示唆を与えてくれました。その知見が今でも十分に役に立っています。このへんのノウハウはうまくまとめられる自信がないので、今後それとなくこのブログに散りばめていこうと思っています。

 

ゲームのUI

 先に書いた通り私はゲームのUIを専門にしています。ゲームのUIというのはゲームという面白い遊びに、ユーザーを引き込んでコミュニケーションするためのもので、ユーザーとゲームシステムがコミュニケーションするためのインターフェイスのことを指します。「インターフェイス」という語についてはニュアンスをうまく伝えるのが難しい語なのですが、平易な書き方で「やり取りのための仕組み」くらいがゲームUIとしては一番近いニュアンスかなと思っています。そのUIを考えるうえで外せないのが「時間」の扱いです。

 

プレイ時間とUI

 ゲームにはユーザーがプレイし始めてから終了するまで、という「時間」があります。この「時間」はとても重要で大変貴重なものです。もちろんUIにとっても。

 昔のアーケードゲームでは単位時間あたりのインカム数(コイン投入数)がビジネスとして重視されました。プレイ開始から、いかに短時間でプレイヤーを満足させるか、またゲームオーバーになっても、コンティニューしたくなるようにするのが課題でした。そのためにはキャラクター選択や必殺技のデモ演出というようなゲームプレイ(体験)とはあまり関係ない画面はインカム数にダメージを与えるとして、徹底的に切り詰められました。とにかくパッと見て必要な情報をシンプルに分かりやすく配置し、短時間に何をどう操作して決定させるかが、UIに課せられた任務でした。100円で満足するには、UIではなくキャラを操作したいですよね。

 残念ながら、どれだけ素晴らしいデザインのキャラセレ画面やアイテム管理画面なんかを操作しても、それを思い出として語るプレイヤーはなかなかいませんし、ゲームをプレイしたという思い出にUIは含まれないものと了解するしかありません。空気のような存在感のUIでユーザーがゲームプレイに満足できれば、そのゲームのUIは素晴らしいUIである。と本気で思っています。

 

 ちなみに「GAME OVER」という表示は、アーケードゲームならではの演出です。その理由のひとつとして、ゲームセンターという公共の場所にカギがあります。乱暴な書き方をすると、ゲームオーバーの文字が表示されたら、さっさと席を譲れ。ということです。あなたの100円でのプレイ可能時間はここで終わったんだよ、と。

 

 アーケードゲームに限らず、このプレイ時間(アプリの場合は操作時間)というものは、プレイする側にとっても、プレイさせる側にとっても大変重要な要素であることは疑いようもなくて、ここの意識が弱いと、必要な操作なのに分かりにくくてモタついたり、目的の状態まで進めていくのに演出の尺が長いといった、テンポの悪いUIを許してしまう恐れがでてきます。

 

 そういえば、UIを操作している時間が貴重であることに気づいた偉い人が、何年か前にUX(ユーザー体験)という言葉をハイライトして、ユーザーがよりシンプルでスマートに目的を達成するためのUI設計を考えましょう。と提案したことで「UI/UX」というパワーワードが俄かに脚光を浴びることになったのだと思っているのですが、ゲームセンターでの教訓を学術論文にでもして発表できていれば、ゲームの世界からUI/UXが語られていたかもしれません。

 

 さてさて、この「時間」というものを意識してUIを考えると、ただグラフィックがそこにあるだけではUIは成り立たないことに気づきます。グラフィックの存在と合わせてそのグラフィックの行方をどうするか、がUIを作るうえで重要になってきます。

 

振る舞いと意味

 ゲームシステムからUIを通じて選べと言われてユーザーは選んで決定し、ゲームシステムはその情報を元に次のフローに進みます。このゲームシステムとユーザーとの対話がスムーズに進むようにするのがUIの役割です。ユーザーに不安を抱かせないように気つけながらいろんな手段でユーザーに選択を促しその結果をフィードバックします。この時の対話で何らかの動き=「振る舞い」を使うとやり取りの効率がぐっと上がります。

 分かりやすいのは決定した項目をハイライトしたり、カーソルを点滅させたりとかです。UIとして画面に表示されるグラフィックはすべて、必ず何らかの振る舞いを持ちます。「意味を持つ」と言い変えてもいいでしょう。パッと出て、パッと消えるのも振る舞いです。ユーザーの目に触れてから消えるまでの存在すべてが振る舞いであり、ユーザーへ伝わる「意味」となるのです。

 動きには当然時間が伴います。時間といっても非常に短い時間ですが、この小さな動き=振る舞い(新しい言葉でマイクロインタラクションとでも言えばいいのでしょうか)がつながってゲーム全体のテンポに影響を与えます。

 

UIデザインというお仕事

 だいぶ回りくどい感じになってしまいましたが、ようやく表題に近づいてきました。

 UIはメタで抽象的な世界から答えを見つけてきて表現することが多いので、「正解」というものはいくらでもあります。その中から「Bestな正解」を、ワインのソムリエのごとく見つけてきて開発チームに提案します。それが受け入れられれば幸せですが、受け入れられなければまた数多の正解の中から次の正解を探す旅に出ることになります。ステージに草を生やしたい。と言われれば草に見えるものを置けばいいのですが、UIにはゲームシステムからの情報伝達という大事な役割があるので、そういった具象的なものをそのまま置くだけでは意味が伝わりにくいです。ユーザーにUIとしての存在意義を疑われたらおしまいです。齟齬やミスリードの無いように慎重に設計する必要があります。どういったタイミングで、どういった情報をユーザーに伝えて判断を促すのがいいのか、どういった振る舞いをすればゲームシステムとの対話になるのか、どこまでが装飾であるのか、こういった部分をひたすら考えます。

 振る舞いも含めてデザインするためには、何らかの動き(アニメーションなど)を検証するところから始めて、Bestな正解を探します。光り方や点滅速度、移動の方向や速度など、ある程度はAfterEffectやDCCツール、Flashなどタイムラインの仕組みを持つツールがあれば検証できますが、それはあくまでもシミュレーションにすぎません。やはり対話には「コール&レスポンス」の心地よさが大事です。そこを実際に動かすことができるのは、ソフトウェアとしてのプログラムということになります。UIパーツの振る舞いを考え、それをプログラマに伝えて組み込んでもらいます。

 動いたら触ってみて感触を確かめます。手触りの悪いところは調整しつつ、仕様要件を満たしているか、また将来追加される仕様に対応できるかなども確認します。こうして限りなく製品に近いモックアッププログラマと一緒に作って、レビューしてもらうのが理想形です。

 プログラマに面倒な動きをお願いしたり、レビューの意見に振り回されたりしつつも二人三脚で作っていくのがUIデザインというお仕事の基本になります。このあたりの具体的なテクニックやノウハウなども、機会があれば書いてみようと思います。

 

 アンリアルエンジン推し

 UIをデザインしてモックアップを作る環境が理想なのですが、そこにはプログラマが必要です。絵にかいた餅を食べられるようにしてくれるのがプログラムなのです。デザインして食べてみておいしいかどうか。これを繰り返してUIデザイナーという職能(=スキル)を高めることができると思います。一人でUI開発するのは難しいです。振る舞いをどうにかしてくれるプログラマの存在が欠かせないからです。

 ただ画面のイメージ画を作って見せても、いまいち具体的な操作感や振る舞いをイメージしてもらうのは、頭の中でシミュレーションできる人じゃないと難しいです。

 

 なんとかして動くものを見てもらいたい、そのための研究としてOff-JTしたいなーと思っていたところにアンリアルエンジンと出会って、すっかり魅了されてしまいました。シンプルで柔軟なアセット管理ができるのも分かりやすいし、作ってみたいUIをすぐに試せる気軽なUMGとWidgetブループリントはもう手離せません。プログラマにお願いする前にプロトタイプを作って検証できるのがとにかく素晴らしいのです。アイディアを形にしやすいのがアンリアルエンジンのビジュアルスクリプトだと思っています。ブループリントの魅力は触ってみて実際に作ってみないと実感しにくいので、言葉で説明するのはやめておきます。UI的にどんなことができるかは、当ブログの記事で確認してもらえればと思います。まだまだこれからも頑張って紹介していくので、興味が沸いてきたならぜひ触ってみてください。

 

  結構な文字量になってきたのでこの辺で筆を置こうと思います。(←古風な言い回しですがこの表現好きです)

 UIデザインって実はとても大変なんです。グラフィックデザインを学んだからといって一朝一夕でできるようなお仕事では決してないことを言いたいがために、時間と振る舞いに重点を置いてみたのですが、いかがだったでしょうか。長くこの仕事をしていると、一家言どころか、百家言くらい言いたいことがあったりするのですが、こちらもまた別の機会にします。感想やらツッコミなどありましたらコメントとかでよろしくお願いします。

 

ではでは みなさん

ステキなUIデザイナーライフを!

今年も当ブログをよろしくお願いいたします

 

 

よいお年を

ついに大晦日ですねぇ。このブログもペースは落ちてますが、なんとかマル2年続けることができました。これも多くの方に読んでいただいているのが、励みになっています。ありがたや、ありがたや。

2年も経つとエンジンのバージョンも随分アップデートされてきました。そろそろ過去記事をメンテした方がいいかもしれないなぁ と思うんだけど、それよりも新しい記事書かないと、という想いがその思いを押しやってしまって結局のところネタを思いつかなくて筆が重くなるという、よくわからない悪循環のような状態になっている今日この頃です。大晦日ということで、小ネタを載せて2017年を締めようかと思います。

 

マテリアルで絵を揺らします。パラメータで制御できるので、いい感じにアニメーションさせればそれなりに使い途はある・・・と思いたい。

f:id:hiyokosabrey:20171231203820p:plain

制御用パラメータは3つ。

  • Period ・・・波の数
  • Amplitude ・・・ 左右の振れ幅  0でまっすぐ
  • OffsetY ・・・ タテ方向のスクロール用

 

真ん中のシマシマのテクスチャは、こんなやつ。

f:id:hiyokosabrey:20171231204249p:plain

8 x 512px のグレイスケールテクスチャです。

あとは、タイムラインからパラメータ用の数値を取り出して、横流しをしてやればOK。

アニメーションを再生して、

f:id:hiyokosabrey:20171231205515p:plain

 

EventTick で取り出して横流しです。

f:id:hiyokosabrey:20171231205555p:plain

この例では、最初からある キャンバスパネル の Pivot は演出に使わないので、Pivot にアニメーションを仕込んでいます。Pivotは XとYの2つしか値を持っていないので、 OffsetYとして 0.5を掛け算して 再利用しています。

 

アニメーションを再生するカスタムイベントが呼ばれると動きます。

f:id:hiyokosabrey:20171231210729p:plain

f:id:hiyokosabrey:20171231210739p:plain

f:id:hiyokosabrey:20171231210747p:plain

うにょ~んと動くので、なかなか楽しいです。

動画でお見せできないのが残念ですが、興味を持っていただけたならぜひ試してみてください。

どこで使うんだろうというネタですが、これで今年は締めさせていただこうと思います。

 

ではでは

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

ステキなUE4ライフを!

 

マテリアルで電光掲示板を作ってみる

オモムロに電光掲示板(流れるやつ)を再現してみたくなって試してみたら、なかなかいい感じになったのでメモっておくことにします。

f:id:hiyokosabrey:20171215214252p:plain

 

たまにゲームで見かけるのが、ドット風のテクスチャでマスクされて、UVスクロールしているやつ。穴のたくさん開いた板の向こうを看板が滑っているようにみえるので残念な気持ちになることがあります。まぁこんなところが気になるのは職業病ですね。

 

・・・

 

 まずテクスチャを用意します。

 

f:id:hiyokosabrey:20171214231224p:plain   ←256x16 px

 

フォントはアンチエイリアスを無しにします。Photoshopの書式設定は以下のとおり。

f:id:hiyokosabrey:20171214231500p:plain

 

UE4のインポート設定は GrayScaleにします。ここで重要なのがフィルター設定。

f:id:hiyokosabrey:20171214231748p:plain

 拡大表示してもドットがボヤけないように、Nearest にしておきます。

 

できたテクスチャを使ってマテリアルを用意していきます。

f:id:hiyokosabrey:20171215200359p:plain

 テクスチャの一部を切り出す(トリミング)ので、TexCoordinateノードのタイリング設定は以下。

  • UTiling: 0.25
  • VTiling: 1.0

これで256x16のテクスチャの内、 64x16 (タテヨコ比 4:1)の部分が目に見えることになります。

Add ノードで値を追加すると、UV値が移動します。そこで移動用の仕組みが以下。

f:id:hiyokosabrey:20171215202244p:plain

Time ノードは、Period という設定値を持っていて、値を設定しておけばその値までカウントしたらまた 0 に戻って・・・を繰り返します。ここではテクスチャサイズを入れておけばいいのですが、カウントアップの速度がそのままスクロールスピードになるので、いったん 1/10 した値を入れておきます。すると、 0.0 → 25.6 でループします。

そしてその値を 10倍することで、 0.0 → 256.0 にできます。

このあとの Floor ノードの手前で 0.0 ~ 256.0 という値になっていれば問題ありません。

さらにスピードアップするなら、 Period = 2.56 で 100倍すればOK。

この状態で見た目にそれっぽくなります。

下はWidgetのキャンバスに Image パーツを置いてマテリアルをセットした状態。

f:id:hiyokosabrey:20171215203515p:plain

パーツのサイズは 1024x256 です。 テクスチャのフィルタ設定を Nearest にするとピクセルがボケずにそのまま拡大されるのが分かると思います。

 

もう少し雰囲気を出していきましょう。

タイリング用のマスクテクスチャを用意します。

 

f:id:hiyokosabrey:20171215203905p:plain  ← 16 x 16 px

 

これをインポートして、先ほどのマテリアルに持ってきます。

f:id:hiyokosabrey:20171215204144p:plain

Multiply で掛けるのですが、そのままだと、↓こうなるので・・・

f:id:hiyokosabrey:20171215204345p:plain

TexCoord先生にタイリングをお願いします。

  • UTiling: 64
  • VTiling: 16

Tilingの値は、1.0以上の場合は、言葉の通り繰り返し回数なのでイメージしやすいですね。

f:id:hiyokosabrey:20171215204714p:plain

いかがでしょうか?かなりいい感じになったと思います。

 

今回のマテリアルはWidget専用というわけではないので、いろいろ応用できます。 

せっかくなので、マテリアルドメインを通常の Surface にしてシリンダーに貼ってみました。

(文字テクスチャの部分切り出しは無しにしています)

Emissiveの値を強めておいて、ポストプロセスでBloomを有効にすると雰囲気アップです。

f:id:hiyokosabrey:20171215211616p:plain

 

 

 

マスクテクスチャのデザインを変えると、ちょっと雰囲気を変えることができます。

f:id:hiyokosabrey:20171215210442p:plain ← LED風

f:id:hiyokosabrey:20171215210504p:plain←ブラウン管風

この色付きのマスクの場合、文字のカラーを変えるといい感じになるのでオススメです。

でちょっと遊んでみたのが冒頭のやつです。

f:id:hiyokosabrey:20171215214252p:plain

かなり雰囲気が出せました。

 

 

タイリングの回数が多くて処理が・・・となるのであれば、マスクテクスチャをあらかじめいくつかタイリングした状態にすれば、回数を減らすことができます。

テクスチャの容量は増えますが、描画の負荷は減ります。

f:id:hiyokosabrey:20171215212135p:plain ← 32 x 32 px

  • UTiling: 64  → 32
  • VTiling: 16  → 8

 

 

今回はこの辺で。

ではではステキな電光掲示板ライフを!

 

 

2枚の絵をマスクで切り替え

このブログもそろそろ2年目を迎えます。よく続いたもんです。さすがにネタに困ってきてる気がしないではない・・・というかちょっと困ってます。

朝、駅のホームで突然ひらめいたりしますが、地下鉄の駅から地上に出たところでスッカリ忘れていたりするので、もうどうしたものか・・・。

 

さてさて

そんな ネタ貧困生活のなかでようやく思いついたのがマスクテクスチャを使った絵の切り替え。どこらへんに需要があるか分かりませんが、工夫次第で面白い表現が出せそうです。

 f:id:hiyokosabrey:20171206041405j:plain

 

ではまず

マスクテクスチャを作ります

解像度はかなり小さく作ります。

40x23 px  ↓これは400%に拡大した状態

f:id:hiyokosabrey:20171205212853p:plain

ノイズを乗せます。このときヒストグラムが確認できるのであれば、確認しながら掛けるといいと思います。なるべく両サイドの分布が少なくなるようにする方がいい感じになります。

f:id:hiyokosabrey:20171205213144p:plain

仕上げにトーンカーブで(0,0,0)と(255,255,255)を無くします。

試せばわかるのですが、無くしておかないと、マスクで使う際に完全な白と黒にならないからです。

f:id:hiyokosabrey:20171205223420p:plain

 このトーンカーブは調整レイヤーで作業すると使い回しができて便利です。

 

 

このテクスチャをUE4にインポートします。

 Grayscale で sRGB を使わない設定にします。

最後に大事なのが、Filter設定。これを、Nearest にしておきます。

f:id:hiyokosabrey:20171205224059p:plain

 

あとは適当な絵を2枚用意してマテリアルを作ります。

f:id:hiyokosabrey:20171205231157p:plain

 ValueStep ノードはPhotoshopでいうところの『2階調化』っていうやつです。

Gradientのピンにグレイスケールの絵を流して、Mask Offset Value のピンで閾値を加減します。

 

これを、Widgetで確認します。

このマテリアルをキャンバスのImageパーツにセットします。

グラフに置いてある Event Pre Construct で ダイナミックマテリアル化しておきます。

f:id:hiyokosabrey:20171205232009p:plain

 

アニメーションのために、隠しパーツをキャンバスに一つ置いておきます。

 この辺の操作は過去記事でもやってたので一応貼っておきます。

limesode.hatenablog.com

このパーツの Pivot あたりにアニメーションを付けます。値は 1.0 → 0.0  になるようにします。

もちろん非表示なので、 Visibility は Collapse にしておきます。

全開の記事では Hidden にしていましたけど、Hidden よりも Collapse の方が処理がかからないそうです。

 

あとはこの隠しパーツ(今回 Invisibleと名付けました)の値を拾って、ダイナミックマテリアルに渡すようにしておいて、

f:id:hiyokosabrey:20171206033128p:plain

アニメーションを再生すればOK。

再生用のイベントを用意しました。

f:id:hiyokosabrey:20171206034225p:plain

 

レベルブループリントで確認用の CreateWidget → Add to Viewport をつなぎます。

そして、Input ~ で再生用のイベントを呼び出せば簡単に確認できます。

f:id:hiyokosabrey:20171206035050p:plain

繰り返し確認するために、リセットするイベントを用意しました。

f:id:hiyokosabrey:20171206035318p:plain

 

では再生してみると・・・

f:id:hiyokosabrey:20171206041024g:plain

(実際はもっと速いのですがGIFの再生速度が限界っぽい)

 

再生速度はタイムラインで調整できます。

ポストプロセスマテリアルに応用すると、画面遷移として使えそうです。

マスクテクスチャをグレイスケールで作れば、StepValue で段階的なアニメーション表現ができるので楽しいです。

今回はデジタルノイズっぽくランダムにしたかったのと、テクスチャを安く作りたかったので、普段あんまり使わないNearestを使ってみました。

 

こんなやつだと

f:id:hiyokosabrey:20171206044958p:plain  64x64px をマテリアルでタイリングしました。

f:id:hiyokosabrey:20171206045323j:plain

同じサイズで円形のグラデーションにすると

f:id:hiyokosabrey:20171206045926p:plain

f:id:hiyokosabrey:20171206045948j:plain

 

階調を反転すると、また違った見え方になります。

 

 

ではでは今回はこの辺で。

ステキな画像切り替えライフを!

UMGの移動アニメーションを作る場合

UMGで移動アニメーションを作る場合、PositionTranslation の2種類があって、表示された見た目には違いがないように感じますが、それぞれ仕様が違うので私は使い分けて使っています。

今回はその使い分けについての私なりの解釈をぐだーと書いてみます。

 

下図は、UMGのキャンバスに置いたImageパーツのDetails(詳細)タブ。

f:id:hiyokosabrey:20171103113340j:plain

まず先に書いてしまうと、

  • Position は レイアウト用
  • Translation はアニメーション用

として捉えています。

実際に使ってみると判るのですが、ポイントは座標の扱い方が違うという点です。

Position は Anchor を基準としたキャンバスパネル内の絶対位置である「居場所」を指定します。一方 Translation は今いる場所からの プラスマイナスした位置という「移動量」を指定します。コトバの意味としても、辞書を見ると translate には「場所」をイメージさせるような訳がなく「翻訳」の他に「変形」という和訳がありました。

カテゴリも Render Transform ですしね。

なので、覚え方としては、

  • Position で指定した場所から Translation で指定した分だけ変形

となります。

「移動」と書かずにあえて「変形」と書いたのは、UMGでは移動も変形として扱っているからです。

3Dモデルで考えると解りやすいのですが、まずモデルには中心(Center)があって、そこから離れた位置に各頂点(Vertex)があります。この各頂点はモデルの中心からの相対位置でデータ化されています。Transform は形状を変形させることになり、変形することは頂点が移動することを意味します。例として頂点4個の四角いメッシュでイメージ図を作ってみました。

f:id:hiyokosabrey:20171103144901p:plain

f:id:hiyokosabrey:20171103144913p:plain

 UMGやFlashのような2DベースのGUI制作に慣れ親しんでいると、この「頂点」があるというイメージは感覚的に身に付けるのは難しいかもしれませんね。

 

ちなみに

キャンバス内でレイアウトを触っていると、値が変化するのは、Position の方で、Translation は、0.0 のままです。

 

 

ブループリントで位置を触る場合

位置を変えることができるノードは2つあります。

Position の方は Canvas Slot 型に キャストしてやる必要があります。

 

f:id:hiyokosabrey:20171103115727p:plain

Image_22 というのはUMGでテキトーに置いたImageパーツです。

 

変数には Canvas Panel Slot型というのがあるので、ブループリント内で繰り返しPosition を触る場合は、変数化しておくと便利です。

f:id:hiyokosabrey:20171103142255p:plain

 

で、結局のところ・・・

移動アニメーションは基本的に Translation で行うと扱いがラクになります。

UMGのキャンバスでのレイアウトの変更や調整がやりやすいからです。

 

例えばフレームインしてくるアニメーションの場合、まず最終表示位置にパーツを並べて位置を決定します。そのあとで、Translation でそこから表示開始位置まで移動するのをアニメーションキーで登録します。この時の値は、いくらか離れた位置を開始位置にして、終了位置は必ず 0.0 になります。開始位置のキーは、単に移動量を表わすことになりとてもシンプルです。

 

後で、レイアウト上の問題が発生してこの最終表示位置をキャンバス内で修正したとしても、調整レベルであればアニメーションキーの修正は必要ありません。これが結構メリットになります。

 

座標の扱いについてまとめると

  • Position は キャンバスに対しての 絶対座標
  • Translation相対座標 または Position からの オフセット位置

ということになります。

 

UMGのAnimationでは Translation で動きをつけ、ブループリント では Position を使って配置する、といった使い方が便利でよく使う手です。

 

 

 今回は以上です

 Position と Translation の使い分けで、迷っておられる方があれば、ぜひ参考になればうれしいです。

 

ではでは ステキな移動アニメーションライフを!