みつまめ杏仁

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

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 の使い分けで、迷っておられる方があれば、ぜひ参考になればうれしいです。

 

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

 

 

UMGのテキストを動かしてみる

UMGでテキストを表示します。キレイにアウトラインフォントが表示されます。

うん。

・・・・。

そう、ちょっと刺激が足りないなと、気づいたのです。

このままで終わっていいのか?テキストブロック!

お前の人生、ただ指示された通りの文字を並べるだけでいいのかよ!

と、中学校の文化祭に行って観劇してたら急にそんな気分になったのでした。

で、

テキストの文字を1文字ずつアニメーションさせてみようと思って遊んでみました。

 

テキトーにWidgetブループリントを用意します。

さっそくキャンバスに、Horizontal Box をひとつ。is Variable のチェックを忘れずに。

f:id:hiyokosabrey:20171020213815p:plain

あと、Size to Content にもチェックを付けます。

で、

ブループリント。

 

まず変数を3つ新しく用意します。

f:id:hiyokosabrey:20171020213710p:plain

上から、

Boolean型の変数は、準備できるまで、 Event Tickに我慢させるためのフラグ。

TextBlock型の配列変数は、文字をバラバラに管理するため。

Float型の変数は、サインカーブのための角度を保持するため。

 

変数が用意できたら、続けて関数を一つ。

関数にも、ローカル変数を3つ。これは関数内だけで利用される変数。

f:id:hiyokosabrey:20171020221553p:plain

上から、

String型の変数は、パラメータとして受け取った文字列を保持しておくため。

Slate Font Info型の変数は、フォントの設定を保持させておくため。

Integer型の変数は、受け取った文字列の長さを保持しておくため。

 

ちょっと画像が大きくなったので、左右で2枚になりました。

f:id:hiyokosabrey:20171020222152p:plain

文字列の長さを、 Lengthノードで調べると、単純に文字の数を調べてくれます。

例えば、"0123456789" のように数字が並んでいる場合、文字の数は10個です。

ForLoop ノードでは、繰り返しの回数を指定する場合に、Index番号という数値で管理します。なので、例えば回数を10にしたい場合、開始 Indexが 0 、終了 Index が 9 となります。

開始 Indexが 5 、 終了 Index が 14 の場合でも、ループ回数に変わりはないのです。

じゃあ、1から始めりゃいいじゃん、ってなるかと思うのですが、最近「ゼロから始める○○」が人気のヒケツ(?)っぽいので、まぁそんな感じです。(実際は座標なんかを計算したり配列を扱うときにゼロから始まっていた方が都合がいい場合が多いのです)

 

なので、ForLoopの繰り返し処理では、文字列の長さを、Last Indexとして使うためには 予め ー1しています。

 

変数の値を参照しにいくたびに 毎回 -1 の計算が入ってしまうのを避けるために、下のようにしています。

f:id:hiyokosabrey:20171020223655p:plain

ForLoopの中を見てみると、First Index は回数をカウントするためにローカル変数で管理されていますが、 Last Index の方は、毎回 つながったピンの値を参照します。

下のようにつないでしまうと、Last Indexピンが値を受け取ろうとするときに、-1の計算が入ってしまいます。

f:id:hiyokosabrey:20171020223825p:plain

この程度たかが知れてますが、普段から意識してないと「チリツモ」になりやすいので、エンジニアと良好な関係を築くために、UI紳士としては意識しないわけにはいかないと思うのです。

はい、流れを戻して続きを。

f:id:hiyokosabrey:20171020225505p:plain

左端のノードは、Construct Object from Class という名のノードです。

↓取り出した直後の状態。

f:id:hiyokosabrey:20171020225745p:plain

Classをセットすると、NONEの部分の表記が変わります。今回はテキストブロックなので、Text をチョイスします。

 

ローカル変数 TempFontの中身は、Details (詳細)タブで設定します。今回はこんな感じ。

f:id:hiyokosabrey:20171020230224p:plain

 

この関数では、テキストブロックをブループリントで生成しています。

そしていつもなら、クリックとキーボードで設定していた内容も、変数と専用のノードを組み合わせて設定しています。一文字づつ処理して、Horizontal Box に並べていくのです。

ひととおり並べ終わったら、ループ処理のあとに、ブーリアン型の変数に True をセットします。

これで関数は完成。

 

つぎにアニメーションの部分。Event Tick を利用します。

関数が呼ばれると、文字列がバラバラになって並べられて、最後に ブーリアン型の変数に True が入ってようやく、このEvent Tick が最後まで稼働します。

f:id:hiyokosabrey:20171020230926p:plain

Event Tickは、 このWidgetブループリントが Viewport に置かれたらすぐに動き出します。関数が呼ばれる前に動き出すとエラーが出るので、必要な処理が終わるまでは、Branchノードでブロックしています。

 %ノードは、 値がずぅーっと加算され続けるのを防ぐためと、円の1周分の角度は360度だからです。

角度から、三角関数を使って 値を計算します。その担当をマクロにしました。

f:id:hiyokosabrey:20171020233958p:plain

Period は カーブの周期(的なもの)、Radius は 半径 です。

中身はこうなってます。

f:id:hiyokosabrey:20171020234221p:plain

三角関数の角度Θ(シータ)にあたる部分は、「ラジアン」(Radians)が基本かと思いますが、ブループリントでは、0°から360°の「角度」(Degrees)で扱うノードも用意されています。

f:id:hiyokosabrey:20171020234801p:plain

マクロでは角度 Degrees の方を使用しています。

 

これで準備はできました。

あとは関数を呼び出して文字列を渡すだけです。

とりあえず確認のために、Event Construct につなぎます。

f:id:hiyokosabrey:20171020235150p:plain

 

これで Widgetは完成です。

 

 

あとはレベルブループリントにて、Viewportに追加するだけです。

f:id:hiyokosabrey:20171020235427p:plain

 

再生してみましょう。

 f:id:hiyokosabrey:20171021000449g:plain

 Screen to GIF というアプリを使ってみました。

ちょっとひっかかるときがあるけど、い感じに撮れてます。

サインカーブを、Y座標にするこんな風に上下にユラユラします。

 

マクロのパラメータをいろいろいじると揺れ具合が調整できます。

Period を大きな値にすると、カーブが細かくなってジグザグします。

Radiusの値を大きくすると上下の揺れ幅が大きくなります。

 

この値を、Shear や Angle にセットしても面白い動きになります。

f:id:hiyokosabrey:20171021001200p:plain

 

 Angleの場合。

f:id:hiyokosabrey:20171021001729p:plain

できたのが

f:id:hiyokosabrey:20171021001745g:plain

 

Shearの場合。

f:id:hiyokosabrey:20171021002328p:plain

動きは

f:id:hiyokosabrey:20171021002352g:plain

ちょっと酔いそう。

 

サインカーブは、プラスとマイナスの値を行ったり来たりするので、どちらか一方だけにするとバウンドするような動きになります。

f:id:hiyokosabrey:20171021003928p:plain

 すると、

f:id:hiyokosabrey:20171021020110g:plain

他にもカラーを変えてみたりもできます。

 

ロード画面くらいしか使える場所は無さそうですが、ちょっとは刺激的になった気がします。なかなか楽しいですねUE。

 

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

 

 

 

 

話しかけるときなんかのマーカーみたいなやつを作ってみる【改】

前回の記事でポップアップする▼マーカーを作ってみたのですが、改造することにしました。

limesode.hatenablog.com

なぜかというと、このタイプのUI表示は同時に複数出ることがなく、常に一つだけが表示されます。前回の作り方では呼び出し元であるActorの配置とタイミング次第では、いくつもスポーンしてしまう可能性があったからです。複数個現れないようにきっちリと管理すればいいのですが、ちょっとフローが複雑になりそうなので思い切って作り変えることにしました。

どうやらプログラム界隈では「シングルトン パターン」なるものがあるようで、同じような感じの扱いができないかな? ということで試してみたのが今回の内容でもあります。

UE4にその仕組みが実装できるのかどうか、自分の頭では見つけられなかったので、完全に我流になります。

 

前回作った、BP_PopMarker をあらかじめワールドに置いておきます。座標は適宜書き換えることになるので、適当な位置でも大丈夫。

f:id:hiyokosabrey:20171017225130p:plain

このブループリントをさっそく改造します。

最初から表示されていない方がいいので Construction Script 内で非表示にします。

f:id:hiyokosabrey:20171017225748p:plain

Set Visibilityノードにある2つのチェックボックスのうち、

Propagate to Children にチェックを付けると、Targetの子階層もまとめて扱うことができます。この場合 Default Scene Root に対して設定しているので、このBlueprintに含まれる全てが対象になります。

 

次に、変数の設定を変えます。

f:id:hiyokosabrey:20171017230356p:plain

前回このName型の変数は、 Expose on Spawn にチェックを入れていました。

これを戻します。

f:id:hiyokosabrey:20171017230648p:plain

この変数は、値を受け取るという役割のはそのままです。

 

次に

Event Graph の Event BeginPlay につないだノードを編集します。

f:id:hiyokosabrey:20171017232016p:plain

 キャストノードの後ろの部分を消します。

そしてキャスト結果にピンから変数を昇格させて作ります。

f:id:hiyokosabrey:20171017232048p:plain

 

続けて、できたばかりのオリジナルWidget型の変数を利用するために、

新しくカスタムイベントを2つ追加します。

まずは表示開始のイベント。

f:id:hiyokosabrey:20171017230845p:plain

表示終了のイベント。

f:id:hiyokosabrey:20171017230854p:plain

用が済んだので変数の中身を空にしています。

 

これでポップするブループリントは完成です。

 

このポップアップマーカー▼の呼び出し元を変えます。

f:id:hiyokosabrey:20171017232910p:plain

このブループリント内で、コリジョンの判定をしていましたが、バッサリ止めます。

f:id:hiyokosabrey:20171017233341p:plain

あとは、変数化していたWidget型の変数を削除してお片付け完了です。

f:id:hiyokosabrey:20171017233627p:plain

スッキリしたところで保存します。

 

これで前回分の改造は終了です。ここからは、新しく追加する作業です。

 

レベルブループリントで

ワールドに置いた BP_PopMarker をレベルブループリントから扱います。

レベルブループリントを開くには、Blueprintsアイコンの横の▼メニューから。

f:id:hiyokosabrey:20171017234332p:plain

開いたら、ワールドアウトライナから、配置した BP_Chair をドラッグ&ドロップします。

f:id:hiyokosabrey:20171017235213p:plain

このノードからコリジョン判定のBindイベントノードを取り出します。

f:id:hiyokosabrey:20171017235915p:plain

Assign On Actor Begin Overlap を選択するとノードが2つ出てきます。

f:id:hiyokosabrey:20171018000239p:plain

このBind~ ノードに、Event BeginPlayノードと、他の BP_Chair をつなぎます。

f:id:hiyokosabrey:20171018000618p:plain

カスタムイベントに下図のようにつないでいきます。

f:id:hiyokosabrey:20171018001436p:plain

タグの有無を判定して存在していれば、ワールドに置いている BP_PopMarkerのポジションを変更して、中のカスタムイベントにタグを渡しています。

カスタムイベントからは、値を2つ受け取ることができます。気になる場合は、Print StringノードにつなぐとActor名が確認できます。Overlaped Actor はこの場合 BP_Chair になります。

 

同様に、コリジョンから出た時のイベントもつなぎます。今度は、

Assign On Actor End Overlap です。

f:id:hiyokosabrey:20171018002618p:plain

Begin Overlap と同じように他の BP_Chair もつなぎます。

f:id:hiyokosabrey:20171018002949p:plain

カスタムイベントには、BP_PopMarker の中のイベント(消去用)を呼び出しています。

これで完了です。

 

 

コンパイルして確認してみましょう。

f:id:hiyokosabrey:20171018004138j:plain

前回と比べて変わることは無いのですが・・・

 

BP_Chair に 追加していた判定のイベントがごっそり無くなったことで、複数を配置したときの容量が節約できています。

シングルトンパターンなんていう身に持て余した言葉を冒頭に掲げたものの、結局は大したことしてなくて、ワールドに直置きしてそれを利用しているだけという・・・

ブループリントインターフェイスも試してみたのですが、インスタンスをうまく経由させることができませんでした。むむむ。力不足。

 

ひとまずこの方法で、もう少し進めてみようと思います。

ツッコミ等あればコメントください。

 

ではでは

ステキにポップする▼ライフを!

 

 

補足

前回の記事を実践している前提で書いたので、端折っているところが かなりあります。

 もし今回の記事から読んで、やってみようと思われる方は、

前回の記事を進めていく中で、BP_Chair を作る際に Boxコリジョンを置くだけOKです。

 

 

 

話しかけるときなんかのマーカーみたいなやつを作ってみる

※ この記事は 内容に誤りがあったため 内容を一部加筆修正しています。 Ver 4.17で検証・作成しています(2019/4/25)

 

今回は、3DのRPGで、NPCに話しかける時なんかに、頭の上につくマーカーみたいなやつを作ってみます。

UIのプロトタイプ的に気軽に試そうと思うので、材料はエンジン内のものだけで作ります。またワールド内に複数配置するのを前提として「タグ」を利用してみます。

 

f:id:hiyokosabrey:20171006002127j:plain

 

新しいプロジェクトから

プロジェクトのテンプレを Third Person にしてスターターコンテンツありで始めます。

f:id:hiyokosabrey:20171004232538p:plain

f:id:hiyokosabrey:20171004231630j:plain

 

ポップするやつを用意

こんな▼三角形のマーカーとキャラ名という構成にします。

まずは名前表示用のWidget Blueprintから。名前は適当で。

f:id:hiyokosabrey:20171006192049p:plain

まずはキャンバスにテキストブロックを一つ配置します。

f:id:hiyokosabrey:20171006190653p:plain

アンカーは上端中央。

f:id:hiyokosabrey:20171006191023p:plain

アライメント X0.5 にするとポジション X0.0 でセンタリングされます。

f:id:hiyokosabrey:20171006191045p:plain

f:id:hiyokosabrey:20171006191205p:plain

isVariable にチェックを付けて、関数で中身を書き換えるようにします。

f:id:hiyokosabrey:20171006191540p:plain

関数のInputs(引数)は、String型やText型でも問題ないですが、値を渡すときのことを考えてここでName型からText型にキャストします。

 

 Widgetブループリントはここで完成です。

 

 

次に、マーカーのブループリント。

Blueprint (Actor型)を一つ用意します。名前は適当で。

f:id:hiyokosabrey:20171006192347p:plain このブループリントがポップアップすることになります。

 

▼のキャラは、プリセットで用意されている Cone(円錐) を利用します。

f:id:hiyokosabrey:20171006192713p:plain

コンポーネントを追加して、サイズをイイ感じに変更します。

f:id:hiyokosabrey:20171006193003p:plain

Location の Zは高さです。基本上向き ▲ なので、Rotation X を回転させて ▼ にします。

ここで点滅させるためのマテリアルを用意します。

f:id:hiyokosabrey:20171006193348p:plain

光源処理はしないので Unlit です。

f:id:hiyokosabrey:20171006193546p:plain

 

これを ▼ に適用します。エディタのDtailes(詳細)パネルにあるMaterials です。

f:id:hiyokosabrey:20171006193835p:plain

続けてコリジョンの設定を変更します。

f:id:hiyokosabrey:20190425235227p:plain

Generate Overlap Events のチェックを外すだけでもいいのですが、このマーカー自体コリジョンは不要なので、Collision Presets を No Collision にしておきます。

 

 

次に、Widgetを追加します。検索すると見つけやすいです。

f:id:hiyokosabrey:20171006194245p:plain

Detailsタブで、作ってあったWidgetをセットします。

f:id:hiyokosabrey:20171006194629p:plain

Widgetのポジションは、▼ の少し上あたりにします。

 

Widgetにもコリジョンの設定があるので、▼同様に外しておきます。

f:id:hiyokosabrey:20190425235227p:plain

 

 

キャラがの用意が整ったので、ブループリントを触っていきます。

 

まず変数を2つ用意します。一つは▼の回転用(Float型)、もうひとつはキャラ名(Name型)を受け取るようです。

f:id:hiyokosabrey:20171006194945p:plain

Name型の変数は、Expose on SpawnInstans Editable にチェックを付けておきます。

f:id:hiyokosabrey:20171006195246p:plain

Expose on Spawn にチェックをつけておくと、スポーンさせられた時点で値を受け取ることができます。

そこで Event BeginPlay でこの変数の中身をWidgetの中の関数に渡します。

f:id:hiyokosabrey:20171006195757p:plain

あとは▼をくるくる回してやります。

f:id:hiyokosabrey:20171006200208p:plain

SetRelativeRotation ノードは 引数の Rotate ピンを分解して使います。

上下逆さまにするために、X軸に固定値の 180 を。 Yは変化しなくていいので 0。

Z軸は Event Tick から出力される値をもらって利用しています。ただ値が小さすぎるので100倍しています。スピードを変えるならこの倍率を調整します。

再生中、永遠に加算され続けるので、 (剰余)ノードを入れて 0~360 で循環するようにしています。

右に続いているのは、キャラ名のWidgetが常にカメラの方を向く処理です。

f:id:hiyokosabrey:20171006200932p:plain

ひとまずこれでポップするやつは完成です。

このブループリントに出現の演出と、消える時の演出を加えるとより豪華になります。

 

NPCのブループリントを仕込む

つぎにNPCとなる、 Blueprint (Actor型)を一つ用意します。名前は適当で。

f:id:hiyokosabrey:20171004232411p:plain

作ったBlueprint は空っぽなので、何かオブジェクトを持たせます。

左上の +Add Componet ボタンでスタティックメッシュを呼び出します。

f:id:hiyokosabrey:20171004233852p:plain

コンポーネントにスタティックメッシュが追加できたら、それを選択して Details(詳細)タブから適当なスタティックメッシュを選択します。とりあえずあのよく見る椅子をチョイス。

f:id:hiyokosabrey:20171004233839p:plain

↓こうなります。

f:id:hiyokosabrey:20171004234113j:plain

ついでにこのモデル自身のコリジョン設定を変更しておきます。

DetailsタブにCollisionの項目があるので、そこの Collision Preset を Default にしておきます。

f:id:hiyokosabrey:20171004234634p:plain

 

もう一つ必要なコンポーネントがあります。マーカーを表示するためのトリガーとなるコリジョンです。

f:id:hiyokosabrey:20171004234941p:plain

Viewportで確認しながら、コリジョンのサイズと位置を調整します。

f:id:hiyokosabrey:20171004235238p:plain

 

この後イベントを仕込んでいきます。

専用のイベントノードを2つ使います。 

f:id:hiyokosabrey:20171006203143p:plain

これを取り出す方法が2つあって、一つはコンポーネントのリストで右クリックする方法。Add Event > Add On ~

f:id:hiyokosabrey:20171006202655p:plain

もう一つは、Detailsタブの下の方にあるEvent項目の緑のボタン。

f:id:hiyokosabrey:20171006203041p:plain

どちらも対象のコンポーネントを選択している状態で取り出すことになります。

 

イベントノードが取り出せたら、ノードをつないでいきます。

 

まずは、On Component Begin Overlap イベントから。

f:id:hiyokosabrey:20190425234628p:plain

 


自身にタグが設定されていれば、▼をスポーンするという流れです。

右端は、Spawn Actor from Class ノードのReturn(戻り値)ピンから、Promote to Variable(変数へ昇格)したものです。

この変数化したものは用が済んだら消す処理で使います。

 

で、さっそく On Component End Overlap イベントで使います。

f:id:hiyokosabrey:20190425231923p:plain

コリジョンから出たらこのイベントが発動して、スポーンされていたマーカーは消えます。

スポーンしてなくても、このイベントは発動するので、Destroyする対象が無いということで、Warning と Error が Outputログに吐き出されてしまいます。中身が有効かどうかを、 Is Valid ノードで調べています。

  

これで、準備完了です。

 

 

ワールドに置いていく

できたブループリントをワールドに配置していきます。

f:id:hiyokosabrey:20171006205158j:plain

置いたら、このNPC(椅子)のDetailsタブからタグを設定します。

タグを設定したいアクターを選んだ状態で、Actor 項目の Tags を探します。

f:id:hiyokosabrey:20171006205441p:plain

ここに名前を入れていきます。

f:id:hiyokosabrey:20171006205736p:plain

他のNPCにもいろんな名前をセットしていきます。

 

再生して動作を確かめます。

f:id:hiyokosabrey:20171006210349j:plain

 

 この方法の最大のメリットは、同じ共通のアセットでも、ワールドに配置してから自由にタグを使って情報管理できる点です。タグは配列なので複数の値を扱うことができます。文字で持たせることになりますが、セリフなどのテーブルを参照するためのIDを仕込んだり、ストーリーの進行などに応じたステータス情報なんかも持たせると便利だと思うのですがいかがでしょうか。

 

f:id:hiyokosabrey:20171006212108j:plain

 

 

今回はこの辺にしておきます。

ではでは ステキにポップする▼ライフを!

 

 

 

ちょっと言い訳とか

だんだん更新間隔が広がっていますな・・・。

いろいろネタを思いつくものの、最近エンジンを起動すると発熱がすごくて、扇風機をすぐ横に置いてるんだけど腕ばっかりが冷えてきて、気合を入れるためのなんかいい感じのBGMを探してるうちに結局寝落ち、みたいな日々が続いていました。

ブログの更新が、忙しい時のストレス発散になってたんだと思う。忙しさが一段落してちょっと時間にゆとりができた途端、滞ってた他のものを消化し始めて、気が付くともう神無月。あと3か月もしたら年が明けてるという・・・

世の中のゲームUIデザイナーの一助になれば、そしてそこからUE4のユーザーが増えて、UE4がUI開発の でふぁくとすたんだーど になればいいなぁ。という壮大な野望を夢見て始めたので、まだまだ頑張らねば。

スクロールテキストを作ってみる

 

久しぶりの更新です。大丈夫、まだ生きてます。

電光掲示板なんかでよくある、長さが足りなくてテキストが右から左へ流れるアレをUMGで作ってみました。ただ流れるだけではなく、端っこをフェードさせます。

f:id:hiyokosabrey:20170826003912p:plain

最近見なくなりましたが、HTML界ではマーキーというタグがあったの思い出しました。

 

まずはマテリアルから。

ちょっと前にヒストリアさんのブログでも紹介されてました ScreenPosition というのを使います。

 

ScreenPositionには ”ViewportUV” と ”SceneTextureUV” の2つの設定値があります。

f:id:hiyokosabrey:20170826090616p:plain

f:id:hiyokosabrey:20170826090628p:plain

公式のドキュメントには大した情報が載ってなくて、Tipsテキスト見ながら試してみたのですが、表示に差がありませんでした。

画面いっぱいサイズのWidgetに、試しに下のようなマテリアルをセットしてみると、

f:id:hiyokosabrey:20170826092128p:plain

U(水平)方向にグラデーションが現れます。

f:id:hiyokosabrey:20170826091929j:plain

ちゃんと調べて検証しないといけないですが、今回はとりあえず ViewportUV にして使ってみることにします。

 

Final Color に 白(Constant 3 Vector)をつないでいるのは、後からWidgetで好きなカラーにセットするためです。

 

というわけで、さっそく今回のスクロールテキスト用のマテリアルを用意します。

f:id:hiyokosabrey:20170826003921p:plain

 

 

キャンバスには、Horizontal Box をひとつ置きます。ブループリントから触るので isVariable にチェックを付けておきます。

f:id:hiyokosabrey:20170826004525p:plain

青い帯は、テキストを読みやすくするための下敷きです。

 

配置したHorizontal Box を動かすので、あらかじめ準備として Vector2D 型の変数を2つ用意してHorizontal Boxの初期位置を入れておきます。1つはポジションをリセットするのに使います。

f:id:hiyokosabrey:20170826005113p:plain

 

新幹線の車内ドアの上にある表示では、いくつかのニュースがつながって流れるので、同じように複数のテキストを一つにまとめる関数を用意しました。

 Text型の配列で結合する方法を見つけられなかったので、いったんString型のローカル変数に格納します。 ForEachLoopでText配列から一つずつ取り出して、String型にキャスト(型変換)しながら格納していきます。

f:id:hiyokosabrey:20170826101144p:plain

Text型の配列を全て、String型にして格納できたら、Join String Array ノードで一つにします。このとき間に挟み込む文字列(Separator)を指定できるので適当な記号やら文字を指定します。

関数内だけで完結して、関数の外に特に再利用されない変数はローカル変数にしておくといいです。ローカル変数にしておけば、この関数の処理が終わった後に内容が捨てられるので安全だからです。

 

 

 今回テキストのみですが、将来的にテキスト以外のもの(アイコンとか)も一緒にスクロールさせることを考えて、テキストブロックは動的に作ります。「動的に」というのは「その都度、必要に応じて」みたいなニュアンスです。

 

ブループリントから動的にいろんなオブジェクトを生みだすために

Construct Object from Class というノードを使います。

f:id:hiyokosabrey:20170826123123p:plain

取り出すと Construct NONE というノード名になるのでご注意を。

NONEの部分は Class によって自動的に変化します。下はTextBlockを設定した場合。

f:id:hiyokosabrey:20170826123415p:plain

 

TextBlockをブループリントで動的に生成するので、普段UMGエディタで設定していたものもブループリントから設定することになります。

そこで、フォントの設定をする関数を用意します。関数の 引数(Inputs)にTextBlock を設定します。

f:id:hiyokosabrey:20170826125048p:plain

テキストブロックに対しての設定を好きなだけ追加します。

f:id:hiyokosabrey:20170826124846p:plain

ここでは「色」と「フォント情報」をセットしています。テキストブロックでは、フォントの情報としてマテリアルを渡すことができるので、Make SlateFontInfo ノードの Font Material のところに 用意しておいた Screen Position を仕込んだマテリアルをセットします。

 

次にテキストをセットする関数を用意します。

ちょっと長いので左右に分けました。

f:id:hiyokosabrey:20170826124012p:plain

テキストを流し込んだら、キャンバスに置いておいたHorizontal Box の子供として追加します。

f:id:hiyokosabrey:20170826130026p:plain

右端のBoolean型の変数は、スクロール開始のためのフラグです。この関数が呼ばれたらテキストがセットされて画面に表示されるので、このタイミングでフラグを True にしています。

 

だいたい必要な材料が揃ったので、スクロールする処理を作ります。

EventGraph の EventTick を使います

これも長いので3つのパートに分けました。

EventTickはViewportに置かれたタイミング(Add to Viewport)で動き始めてしまうので、まずはスクロールするかしないかの判定をします。

f:id:hiyokosabrey:20170826131518p:plain

 Float型の変数を用意して、Delta Time を自身に加算していきます。

これは テキストが画面に表れていきなりスクロールすると読めないので、2秒待つようにするための待ち時間をチェックする変数です。

 

フラグが True になって、さらに2秒経ったら、スクロールし始めます。

EventTick によって、毎フレームこのノードたちが処理されるので、座標を加算してはHorizontalBoxのポジションを更新していきます。

f:id:hiyokosabrey:20170826132236p:plain

テキストの長さ(=HorizontalBoxのサイズ)分のスクロールが終わって画面から消えると、ポジションをリセットします。そのためにちょっと変な計算をしています。

f:id:hiyokosabrey:20170826133842p:plain

例えば、テキストの長さが 1000 だった場合、ポジションが -1000 になると画面から消えることになります。ここで問題になるのが、ポジションはマイナスの値。サイズはプラスの値ということです。符号を変える方法はいくつかあります。マイナスの値は ABSノードや -1 を掛けたりしてマイナスを打ち消すことができます。そこでポジションと長さを比較して判定すればいいのです。でも今回は足し算で済ませています。毎フレーム高速に処理するためには省略できるものはしましょう。

文字のサイズ的にピッタリ 0 にはほぼならないので、0以下のマイナスの値なったらスクロール終了ということにしています。

 

スクロールが終了したら、変数の値とポジションをリセットして次に備えます。

f:id:hiyokosabrey:20170826135256p:plain

 

これでWidgetは完成です。

実際に表示を確認してみます。

レベルブループリントに表示する仕組みを用意します。

いつもの Create Widget ノード から、Add to Viewport へのコンボ。

そこに、あとから中の関数を呼ぶためにReturn Value を変数化してものと、表示位置と表示サイズを設定するノードをつなげます。

f:id:hiyokosabrey:20170826202446p:plain

 仕上げに、テキストを渡す部分。

とりあえずスペースキーを押すと表示されるようにしました。

f:id:hiyokosabrey:20170826202830p:plain

 

完成です。

GIFにしてみました。コマ数が少ないので滑らかじゃないけど。

f:id:hiyokosabrey:20170826205454g:plain

 

これを商品レベルにするには、まだまだ必要な仕様やエラー対策なんかがありますが、ちょっとしたプロトタイプなら十分かなと思うのですがいかがでしょう。

 

ではでは

UI開発者の紳士淑女のみなさま

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

 

ついでに UIネタも募集中!

 

 

Widgetを3Dで扱うときに中の関数を呼び出す方法

いつのまにやらセミの声が凄まじい今日この頃、ふと前回の記事更新から随分空いていたことに気付きました。ようやくエディタのバージョン4.16をインストールしました。Widgetに新しいイベントが追加されてたんですよね。Widgetを3Dで扱うときに、EventConstruct の動作するタイミングが悩ましかったのですが、改善されていたらいいなと思いちょっとだけいじってみました。簡単な実験をしてみた結果、特に変わっていない印象です。また後日判ったことがあれば記事にしていきたいと思います。

 

さてさて今回はWidgetをWorld空間に3Dで表示する際に、中の関数やら変数にアクセスする方法をメモっておこうかと思います。

f:id:hiyokosabrey:20170723224553p:plain

Widgetアセットをプレイヤーや、背景と同じWorld空間を置く場合、2種類の置き方があります。Actorなどのブループリントに、Widgetコンポーネントとして持たせてしまう方法と、

f:id:hiyokosabrey:20170723224258p:plain

Add Widget Component ノードを使う方法です。

f:id:hiyokosabrey:20170723224007p:plain

どちらにせよ、どちらもWidgetコンポーネントという形になります。また、大抵ブループリントActorでくるむことになります。

ここでいう「くるむ」というのは、あくまでも本体はWidgetであって、Actorブループリントは3Dで置くための入れ物というイメージで使っている言葉です。

 

ただ置くだけならいいのですが、Widgetを置くからには大抵がUI表示のはず。そうなるとゲージやらテキストやらということになるので、内容のセットアップや更新に関数を使うことになるかと思います。その際にこのWidgetコンポーネントがちょっと面倒なのです。

Widgetを3Dにして扱うときは、このWidgetコンポーネントの状態になります。この状態だと中の関数や変数にサクッとアクセスできません。アクセスするにはキャストが必要になります。

このとき必ず必要なノードがあります。 Get User Widget Object ノードです。

一旦 UserWidget型 にした後、改めて本当の姿であるWidgetにキャストします。

下の図は、MyWidget3Dという名前のWidgetを用意した場合の例です。

 

まずは、Widgetがブループリント内のコンポーネントにしてある場合。

f:id:hiyokosabrey:20170723230138p:plain

つぎは、Add Widget Componentノードから追加した場合。

f:id:hiyokosabrey:20170723230157p:plain

キャストが成功したら、キャスト後の値を Promote to Variable(出力ピンの上で右クリック)で変数化しておくと便利です。以後その変数からドラッグすれば、中の関数や変数にアクセスできるようになるからです。

 

例)

f:id:hiyokosabrey:20170723233121p:plain

 

Widgetブループリントで作ったアセットを 3DのWorld空間に置こうとすると、WidgetComponentの状態で置かれる。

そのWidgetの中にアクセスするときは、いったんUserWidget型にしたあと、それぞれのWidget型にキャストしてやる必要があるということになります。

f:id:hiyokosabrey:20170725000413p:plain

ちょっと面倒ですが、この方法を使えば3DのUIも怖くない。と思うのですがいかがでしょう。

 

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

ステキな立体UIライフを!