みつまめ杏仁

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

UI ボタンでカメラを切り替える《前編》

突然ですが、ブループリントのタイムラインノードってものすごく便利なのです。

f:id:hiyokosabrey:20190418232904p:plain

UMGには専用のタイムラインが装備されていますが、UMG以外でUIのインタラクションを表現する際に利用します。

ただトラックに直接的な値のKeyを打ってしまうと、とたんに汎用性が無くなってしまいます。

先日のぷちコン第11回でも使った方法なんですが、ちょっと扱い方を工夫するだけで汎用性が高くなってさらに調整がラクになる方法があるので記事にしておくことにします。

 

賢明な読者諸兄はすぐに気づかれるかと思いますが、種明かしをするとこれです。

 

f:id:hiyokosabrey:20190417213555p:plain
 

タイムラインノードから出てくる値は、0.0 ~ 1.0 のみ

 この1個のタイムラインを値を煮るなり焼くなりして使い回すのです。

 

掛け算したり、

f:id:hiyokosabrey:20190417214708p:plain

↑この場合、0.0 ~ 5000.0 の値でアニメーションします。

 

また 0.5から引き算して、2倍すると、 -1.0 ~ 1.0 の値のアニメーションが可能。

f:id:hiyokosabrey:20190417215237p:plain

 

しかも、カーブを調整すれば好みのイージングも作れます。

f:id:hiyokosabrey:20190417214336p:plainf:id:hiyokosabrey:20190417214343p:plain

 変に計算が増えると処理への負荷が無視できなくなりますが、ほどほどに、汎用的に使えるカーブを効率よく使えば、調整にかかる時間が減るのでおススメです。

 

さらにこれを便利に活用するためのノードが、Lerp 系のノード

f:id:hiyokosabrey:20190418233447p:plain

 

扱う型専用にいくつか用意されているようです。

入力ピンの Alpha に 0 ~ 1.0 の数値を入れることで 同じく入力ピン A と B の2つの違う値についてその途中の値を取り出すことができます。例えば、Alphaに 0.5 と入れると、A と B のちょうど中間の値がReturnValueから取り出せます。0 だと A に、1 だと B に近い値になります。

 

Vector や Color のような複数の値を持っている場合で、同時にアニメーションさせる場合にとても効果的なのです。

 

ちなみに Lerp は Linear Interpolate の略で、 漢字で書くと「線形補間」です。

ですがタイムラインのカーブを使えば、変化量が線形じゃなくなります。

 

今回この仕組みを使って、UIのメニューに合わせてカメラを切り替えるのをやってみます。

 

切り替えUIメニュー

まずメニュー用のWidgetから。メニューといっても簡単に四角いボタン的なものが並んでいるだけのものです。

そのボタン的なものは、さくっと簡単に UMG の Button というコンポーネントで作ることにします。まず Button を左のリストから探してキャンバスに 配置します

f:id:hiyokosabrey:20190608111755p:plain

 Anchor は ストレッチ(親要素に合わせて最大まで拡大)でドーンとスクリーンサイズに。Anchor を変えただけでは変化しないのでパラメータを変えます。

Button の Slot(Canvas Panel Slot) は ↓ こんな感じ。

f:id:hiyokosabrey:20190419234722p:plain

 

中にTextBlockを子供として持たせます。

f:id:hiyokosabrey:20190419234037p:plain

TextBlockは ↓ こんな感じ

f:id:hiyokosabrey:20190419235053p:plain

階層構造は↓下のようになってます。

f:id:hiyokosabrey:20190419234201p:plain

 

ここで、クリックイベントを作成します。

配置した Button のDetails(詳細)パネルの下の方に緑色のボタンが並んでいるので、

On Clicked のボタンをクリックします。

f:id:hiyokosabrey:20190419235431p:plain

 強制的に編集モードがGraphモードに切り替わります。

f:id:hiyokosabrey:20190420003037p:plain

イベントノードが置かれていますが、一旦置いておきます。

 

Integer型の変数をひとつ追加します。

f:id:hiyokosabrey:20190420003738p:plain

自身が何番目のボタン番号かを受け取っておくためのものです。

 

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

Inputピンに、Integer型とText型を追加して、作っておいた 変数 と TextBlock にそれぞれつなぎます。

f:id:hiyokosabrey:20190420004111p:plain

 

次はイベントディスパッチャーを用意します。

f:id:hiyokosabrey:20190420004632p:plain

Inputsのところで+ ボタンを押してInteger型のピンを追加します。

このイベントディスパッチャーを、On Clicked イベントにつなぎます。

イベントディスパッチャーをグラフにドロップすると小さなコンテキストメニューがポップするので、 Call を選択します。

f:id:hiyokosabrey:20190420005034p:plain

f:id:hiyokosabrey:20190420005134p:plain

クリックされたら、自分が持たされているボタン番号を返す仕組みです。

コンパイルして保存します。これでボタンWidgetは完成です。

f:id:hiyokosabrey:20190608112158p:plain

 

 

ボタンWidgetを配置するWidget

次にボタンを並べるための親になるWidgetブループリントを用意します。

キャンバスに HorizontalPanel をひとつ配置します。

f:id:hiyokosabrey:20190420005733p:plain

Slotはこんな感じ。

f:id:hiyokosabrey:20190420010124p:plain

このHorozontalPanelに、先に作ってあったボタンのWidgetを追加します。

既に作成済みのWidgetブループリントはアセットになっているので、

UserCreated カテゴリで探すと見つかるはずです。

それを Hierarchey パネルの HorizontalBox 以下にドロップします。

とりあえずカメラを5台置く予定なのでその数ぶん追加します。

f:id:hiyokosabrey:20190420010933p:plain

追加したらそのまま、まとめて選択状態にします。

f:id:hiyokosabrey:20190420015453p:plain

レイアウトの設定を変更します。

Size が 初期状態でAuto になってるのを Fill に切り替えます。

f:id:hiyokosabrey:20190420015626p:plain

HorizontalPanelにぴっちり並んでくれるはず。

f:id:hiyokosabrey:20190420015842p:plain


キャンバスはこのくらいで。

 

グラフの方を編集します。

まずは並べたボタンたちを一旦配列にします。配列にした方がForEachLoopが使えるのでこ後でちょっとラクができます。

ざっくりですが手順をGIFにしてみました。

f:id:hiyokosabrey:20190421092553g:plain


次にボタンのラベルをテキスト型の配列で用意します。

f:id:hiyokosabrey:20190421170012p:plain

一度コンパイルすると、DefaultValue(初期値)がセットできるようになります。

 

ここで ForEachLoopの出番です。

f:id:hiyokosabrey:20190421202616p:plain

右端のノードは、イベントディスパッチャーが存在することが前提で、そのイベントディスパッチャーにBind(バインド:紐づけ)することが可能になります。そうすることで、ボタンのWidgetからイベントディスパッチャー経由で通知を受け取ることができます。要するにボタンが押されたら、カスタムイベントが実行されます。

 カスタムイベントにはとりあえず今は何もつなげないで、コンパイルしてみます。

すると、キャンバスが変化します。

f:id:hiyokosabrey:20190421203109p:plain

Event Pre Cnstruct につないだ処理は、Play していなくてもコンパイルした時点で、キャンバスに配置したものに影響を与えることができます。


 Widgetは一旦ここまでにします。

 

 

 

カメラの設置

次はカメラとステージを 用意します。

準備としてレベルに、カッコイ風景とカッコイイオブジェクトを設置します。

 

f:id:hiyokosabrey:20190423011937j:plain


レベルに直接カメラを5台配置。アングルを決めます。Field Of View(視野角)も調整します。

 

前編はここまで。

後編は、メインカメラの作成と制御を作っていきます。タイムラインは後編で登場します。

 

ではでは

 

 

 

ゆらゆらするマテリアル

 なんとか第11回ぷちコンに応募することができました。今回はギリギリまでかかってしまってキツかった。今使ってるPCではパワー不足だということが思い知らされた感があって寂しくはあるけど、あきらめた表現がたくさんあったのもまた事実で、もう買い替えをためらっている場合ではないのだと強く思った次第です。なんてことを書いてますが、かなりの部分は自分の頭の悪さだったりして・・・すみませんマシンパワーのせいにしました。てへぺろ

 実際シェーダーコンパイルに時間がかかり過ぎたのと、半透明に落とす影の調整に時間がかかり過ぎました。

 

 応募した動画を貼っておきます。


【第11回UE4ぷちコン応募作品】 ちいさなうきわ。

 

 動画編集はいまだに不慣れなので、編集に時間を掛けられないと判断。実際にプレイしたキャプチャをそのままノーカットでアップしました。さすがに前後の黒い余白時間をカットするくらいはしてますが、ほんとそれだけです。

 なので、画面遷移やUI表示は職業柄それなりに頑張って作ったつもりです。

 

まぁそんなこんなで、ブログの更新が止まっていたわけですが、久しぶりに書こうと思います。ネタはぷちコンからで、仕組み自体は過去記事でも紹介したものの応用になります。

f:id:hiyokosabrey:20190403223820g:plain

ゴールした時の誉め言葉表示です。

この水の屈折のような表現。ディストーション(歪み)エフェクトとも呼ばれるようですがマテリアルで簡単に作ることができます。

 

 まずは ゆらゆら させるためにはランダムな2D素材が必要です。Noise ノードを使うとテクスチャが不要にできるのですが、やっぱり滑らかさが欲しいので今回 Photoshopを使ってテクスチャを用意するところから説明していこうと思います。

 

あの有名なフィルタを攻略する

ランダムといっても大きなテクスチャはそのままテクスチャメモリの負担となるのでなるべく小さく、かつタイリングできるように作ります。

そこで登場するのがおなじみのフィルター「雲模様1

f:id:hiyokosabrey:20190403230040p:plain

ちなみに↑これは、 512x512 で作成したものを 50%に縮小した状態です。

このフィルターは、2のべき乗で作成すると上下左右がつながったシームレスな状態になります。

フィルター > その他 > スクロール を使うとつながりが確認できます。

f:id:hiyokosabrey:20190403230611p:plain

2のべき乗というのは、2を何乗かした値で、2、4、8、16、32、64、128、256、512、1024・・・という数字です。縦横をこの数の解像度にすると見事シームレスなテクスチャの完成です。ちなみに他の解像度で雲模様を作ると、つながらなくなります。

f:id:hiyokosabrey:20190403231252p:plain

これは 250x250で作成してスクロールさせた状態。よく見るとつながっていないのが判ります。下の図はニアレストネイバーで400%に拡大した状態。

f:id:hiyokosabrey:20190403231641p:plain

 

これが「雲模様1」の特徴です。

ちなみに、この「雲模様1」は、フィルタを掛ける際に、描画色背景色の2色を使って作られます。なので、今回のようにモノクロでしっかりと階調差を出したい場合は、直前に D キーを押して、白黒にしておくのをお勧めします。

f:id:hiyokosabrey:20190403232223p:plain

 

あと、注意したいのが「解像度」です。雲模様フィルタは、密度の調整ができないので、解像度でコントロールすることになります。

f:id:hiyokosabrey:20190403233518p:plain

ヒストグラムで比較するとさらに差が分かりやすくなります。

という訳で濃淡の散らばり具合を考慮して今回は 1024x1024で進めます。

 

 

素のままだとノイジーなので、ここから加工していきます。

水の揺らめきなので、もっと滑らかな感じが理想。

ボカしたり、明るさの中間値を掛けると速いのですが、この状態でかけると、せっかくシームレスにしたのが台無しになってしまいます。フィルタはドキュメントの上下左右がつながっているなんて気にしないからです。

そこで、面倒ですが一旦 手動でシームレスな状態にします。

 

まず 新規ドキュメントを 1024x1024で作成して「雲模様1」を使用します。

f:id:hiyokosabrey:20190403235506p:plain

この状態で、全選択(Ctrl+A) からの コピー(Ctrl+C)までを実行。クリップボードに入れた状態で、カンバスサイズを変更します。

f:id:hiyokosabrey:20190403235842p:plain

するとこうなります。↓

f:id:hiyokosabrey:20190404000004p:plain

ここからクリップボードに入れたのをペーストしていくのですが、ちょっとだけ時短できるぷちテクニックを紹介しておきます。選択範囲を作ったペースト方法です。

まず左上に貼り付けたい場合、マウスを下図のように外に向かって適当に動かします。

f:id:hiyokosabrey:20190404001021p:plain

すると、

このような選択範囲になるので、ここでペースト(Ctrl+V)します。

f:id:hiyokosabrey:20190404001305g:plain

これを4隅で行います。

f:id:hiyokosabrey:20190404001717p:plain

上下左右も同じ要領で適当に選択範囲を作って、

f:id:hiyokosabrey:20190404203509g:plain

ペースト&ペースト。

f:id:hiyokosabrey:20190404203731p:plain

 

多少ずれても中央揃え機能を使えばビシっと隙間なく並びます。

f:id:hiyokosabrey:20190404002452p:plain

アナログな手操作を確実でブレのない結果にするのが大好きなので紹介しましたが、この時点でピクセルがずれていなければどんな方法でもOK。Photoshopは作業中の表示倍率がキリの悪いときはかなりの確率でピクセルスナップが甘くなるので、こういった倍率に関係なく確実な操作は重要です。

 

 この9枚がビシっと並んでいる状態でようやくフィルタを掛けます。

せっかくタイリングするように並べたので、ランダム系のフィルタはNG。あくまでもピクセルに合わせて均等に掛かるタイプのフィルタを使います。

 

今回は、明るさの中間値 を掛けてから ぼかし(ガウス)を掛けました。

f:id:hiyokosabrey:20190404003607p:plain

ここで解像度を落とします。

最終的に 256x256 のテクスチャにしたいので、256x3 = 768

768x768 に縮小します。もちろん縮小されるときにもピクセルにフィルタが掛かります。

f:id:hiyokosabrey:20190404004304p:plain

ここで、カンバスサイズを使って 周りの 8枚をカット、中央の1枚だけにします。

f:id:hiyokosabrey:20190404004525p:plain

シームレスになっているかどうか、「スクロール」を使って確認してみましょう。

f:id:hiyokosabrey:20190404004917p:plain

つなぎ目が見えなければ完璧です。

 

これをリニアなグレースケールテクスチャとして、UE4に持っていきたいので、ドキュメントをグレースケールに変更します。イメージ > モード > グレースケール を選択。

f:id:hiyokosabrey:20190404005241p:plain

 

おそらくポップアップが表示されるので、カラー情報は破棄します。

f:id:hiyokosabrey:20190404005606p:plain

 

チャンネルが 「グレー」だけになったらOK。

f:id:hiyokosabrey:20190404005812p:plain

 

 あとは、これをTarga フォーマット(拡張子 .tga)で書き出せば UE4 にインポートできます。

 PNG形式はチャンネルが一つだけ(SingleChannel)という仕様を持っていないため、PNGで保存した際にRGBA32ビットに戻されてしまいます。なのでグレースケールテクスチャの場合は、PNGは使っちゃダメです。チャンネルが一つということはそれだけテクスチャのメモリが1/4になるということで節約になります。

 

今回よりランダム感を出したいので、もう一枚用意します。

 

f:id:hiyokosabrey:20190404205000p:plain f:id:hiyokosabrey:20190404205011p:plain

 ↑ Web用にPNG形式になってますが右クリックしてDLしてもらってOK

この2枚をUE4にインポートします。 

 

いざUE4

 インポート設定はこんな感じです。

f:id:hiyokosabrey:20190404213401p:plain

今回 sRGB のチェックは外しているので、リニアグレースケールテクスチャとして扱うという意味になります。これはPhotoshopでのカラー設定によって書き出す際の補正があるか無いかで決めます。特に何も設定をいじっていなければsRGBにチェックが付いていると思いますが、今回は特に問題ありません。

 

 ちょうど一年前の記事ですが一応過去記事を貼っておきます。

limesode.hatenablog.com

これを使ってマテリアルを作ります。

Create Material して中にテクスチャをドロップします。

f:id:hiyokosabrey:20190404220627p:plain

 

あ、揺らすためのテクスチャを忘れていました。せっかくなんで。

 

f:id:hiyokosabrey:20190404223919p:plain

 

これをつなぐとこうなります。

f:id:hiyokosabrey:20190404223544p:plain

 速度は左のPannerノード で調整しつつ、揺れ幅というか揺れの度合いは、TexCoordノードで調整します。

参考までに今回の値。

f:id:hiyokosabrey:20190404224930p:plain

さらに適応する量は、真ん中のScalarParameterValueで調整します。このパラメータノードは、Widgetブループリントから値を受け取って反映する役割のノードです。

雲模様のコントラストや濃淡によりますが、今回の値はこんな感じ。

まず、Amount: 0.15

f:id:hiyokosabrey:20190404225807g:plain

かなり揺らめいてます。

次は Amount: 0.1 だいぶ落ち着いてきました。

f:id:hiyokosabrey:20190404230015g:plain

Amount: 0.025

f:id:hiyokosabrey:20190404230110g:plain

もちろん 0 にすると静止します。

 

ちなみに 0.5 はまったく読めません。

f:id:hiyokosabrey:20190404230555g:plain

これだけで一つミニゲームが作れそうです。

なんて書いてあるでしょうか?さぁ早押しでお答えください! みたいな。

ただあまり揺らすと端の切れてる部分が目につくようになるので注意が必要です。

 

真ん中上の、Subtract(引き算)ノードでは、グレースケールテクスチャからやってきた値を調整しています。

f:id:hiyokosabrey:20190404232821p:plain
ここでいう調整というのは、0~1 という範囲を、幅を変えずに -0.5~+0.5 にすることです。テクスチャの黒は 0.0、白は 1.0なので、このまま足し算して使うと、揺れはしますがプラスの方向にしか揺れないので、結果的にテクスチャ全体がプラス側に寄ってしまいます。それをプラスとマイナスの距離が均等になるようにしているのです。

 

マテリアルはこれで完成です。

 

ちなみに、↓こんなテクスチャだと。

f:id:hiyokosabrey:20190404233848p:plain

こんな感じにできます。

f:id:hiyokosabrey:20190404234059g:plain



 

Widgetでフェード

まずキャンバスに、Imageを配置します。

f:id:hiyokosabrey:20190404234621p:plain

配置したら、Detailタブから、Appearance > Brush > Image の部分に用意したマテリアルをセットします。

f:id:hiyokosabrey:20190405000649p:plain

 

さらにもう一つ、Imageをキャンバスに追加します。

f:id:hiyokosabrey:20190405003508p:plain

これは描画しないのでVisibilityを Collapseにしておきます。

f:id:hiyokosabrey:20190405003342p:plain

ここでアニメーションを用意します。

 

アニメーションさせるのは2つ。

一つは、Collapseにした方の Pivot。もう一つは、表示する方の Render Opacity

f:id:hiyokosabrey:20190405010528p:plain



つぎにブループリントを用意していきます。

 

初めから置かれているイベントノードをそのまま利用することにします。

Event Pre Constructから。

f:id:hiyokosabrey:20190405010744p:plain

Image にセットしているマテリアル(Static)をいじるには、マテリアルを、Material Instance Dynamic型 にする必要があって、Get Dynamic Material ノードを使うと型変換しつつ、置き換えてくれます。この変換処理を頻繁に行いたくなくて、一度きりで十分なので、ReturnValueから Promote to Variable(変数に昇格)させています。

 

Event Construct。

f:id:hiyokosabrey:20190405011947p:plain

アニメーションの再生が終わったら、後片付けしてViewportから姿を消します。後片付けといっても変数を空にしてマテリアルへの参照関係を解消するだけです。

 

最後に、Event Tick。

f:id:hiyokosabrey:20190405013151p:plain

 

Widgetは完成です。

 

テスト用の新規レベルを作ってテストしてみましょう。

レベルブループリントに Create Widget ノード と Add to Viewport ノードをつなぎます。繰り返し確認したいので、Inputノードで何度でもWidgetを呼び出せるようにします。とりあえずスペースキー。

f:id:hiyokosabrey:20190405013900p:plain

 

再生してみます。

f:id:hiyokosabrey:20190405014037g:plain

いい感じです。青い背景を置いたので、マテリアルのBlend Mode は Additive に変更しています。

 

 

シームレステクスチャのパターンを工夫したり、タイリングや揺れ加減を調整したり、まだまだ応用できそうです。

 

ではでは

今回はこの辺で

ステキなゆれゆれマテリアルライフを!

 

3Dオブジェクトの上にWidgetをマーカーのように表示できたけどどうなってるの?なんか計算がややこしいのだけれど。

という長いタイトルを付けるのが最近のトレンドぢゃ、とじっちゃが言ってたのでさっそく実践してみたけど、なんというか全然キャッチーにならないのはセンスがないから?などと架空の祖父まで召喚してくだらない言い訳をつらつらと書きながら花粉の猛襲に苛まれる目をひたすら擦りながらキータイプもままならない状態でややこしい記事を書こうとしている折、皆様ますますご健勝のことと存じます。

さてさて前回はとりあえず動くところまでのチュートリアル的な記事を書きました。

少ない脳みそを駆使して解説をしてみようと思います。実際はこうやって書きながら自分の頭を整理してログを残すのが目的だったりします。

 

 さてさて

今回の処理で扱う重要な数値は以下の5つ

  • 描画のための画面サイズ  → Get Viewport Size
  • 追随するWidgetのサイズ  → Get Desired Size
  • 表示スケール  → Get Viewport Scale
  • アクターの表示位置  → ConvertWorldLocationToScreenLocation
  • 最終表示位置Set Position

 

 これらの値があれば計算できるのですが、ひとつ厄介な問題があります。それは最終的な表示サイズが必ずしも画面の大きさと同じとは限らないという問題です。

 たとえば開発中のエディタ解像度を 1920x1080 で進めたとしても、実際遊ばれる環境は、1080pじゃない場合が普通にありえます。フルスクリーンにしろウィンドウにしろユーザーに任されていて遊ぶ環境によって変わるため、UE4では表示する際に、表示されている解像度に応じて一定量のスケール値を掛けることで、元のレイアウトが崩れないように描画してくれます。

 また表示する際に指定する座標は、描画のための画面サイズであるエディタ解像度に準拠するので、スケールを掛けないように指定する必要があります。

 スケールが掛かっていたり掛かっていなかったりする値をうまく整理しながら計算しないといけないのです。

 

開発環境にてエディタ解像度を 1920x1080 にして、画面には 1280x720で表示している場合、上にあげた5つのノードで扱う値は、以下のようになっています。

 

f:id:hiyokosabrey:20190310012023p:plain

Get Viewpor Size は表示されている解像度です。(基本的に可変します)

Get Desired Size にはキャンバスに置いたときの値で、スケールが掛かっていません。

 

f:id:hiyokosabrey:20190310010520p:plain

 

f:id:hiyokosabrey:20190310012429p:plain

 

ここまではGET。最後にSET。

 

f:id:hiyokosabrey:20190310013029p:plain

 

このようになっているので、@ghosticgames さんの手順をみてみると、基本的に スケールの掛かった ViewportSize ベースで計算して、表示位置が確定した後に ViewportScale で割り算して、1920x1080空間用に合うようにしています。

f:id:hiyokosabrey:20190310014617p:plain

 

Get Desired Sizeで得た追随用パーツのサイズに ViewportScaleを掛けているのは、スケールを揃えないとこの後の計算がおかしくなるからです。

f:id:hiyokosabrey:20190310014943p:plain

 

ではこの辺で Clampさんのお仕事紹介と行きましょう。

Clampは3つの入力ピンがあります。

f:id:hiyokosabrey:20190310125803p:plain

Value から入った値が、Min と Max の範囲を越えても、Min(下限) と Max(上限) の範囲から出ないことを保証してくれるという代物。

下図はイメージ。

 

f:id:hiyokosabrey:20190310131747p:plain

例えば、Max に 1.0 が設定されている時に、 Value が 2.5 だとすると、強制的に 1.0 になります。

 

 この仕組みを使って、表示座標に制限を付けるのです。

 

 

f:id:hiyokosabrey:20190310133059p:plain

 アクターの表示位置を3D→2Dに変換する ConvertWorldLocationToScreenLocationノードは、スクリーン座標の限界を超えた値も返してくるので、Clampノードにスクリーン座標の最小値、最大値を設定してやります。

 このとき、追随するWidgetがはみ出さないないようもしたいので、そのぶん内側に制限を付けることになります。

 

f:id:hiyokosabrey:20190310145306p:plain

 

ViewportSize から 追随するWidgetの表示サイズの半分のサイズを内側に入れればよいということになります。改めてノードを見てみるとこうなってました。

f:id:hiyokosabrey:20190310145815p:plain

Local Desired Screen Location はアクターのスクリーン座標です。Viewportの左端は 0 から始まるので、 Min は 追随するWidgetの半分のサイズになります。Max はViewportサイズから 追随するWidgetの半分を引き算すれば求まります。

 

これで、画面内から絶対はみ出さない仕組みが実現できます。

 

 

ということで、ここからは、オマケの仕組みを組み込んでいきます。

f:id:hiyokosabrey:20190310154211p:plain

グラフを開いて、空いているところに、表示する値を受け取るためのカスタムイベントを準備します。

f:id:hiyokosabrey:20190310193804p:plain

カスタムイベントは Float型の ピンを追加します。

f:id:hiyokosabrey:20190310194218p:plain

 

数値に単位の文字「 m 」をくっつけたいので、FormatTextノードを使います。

このノードは、定型のテキストに変数を差し込むことが出る便利なノードです。

{ }でピン名を囲って使います。上の例では、{0}m と入力しています。⑤

 

過去記事にもう少し詳しく書いています。

limesode.hatenablog.com

 

UE4の単位は、Project Settings > Editor > Appearance で設定されています。 

f:id:hiyokosabrey:20190310194925p:plain

 デフォルトでは cm(センチメートル)に設定されています。

 今回 単位を m(メートル)にしたいので、100で割ります。⑥

 割り算の結果と FormatTextノードを直接つなぐことが可能なのですが、小数点の桁数を変更したいので、 ToText (Float)ノード を利用します。⑦

この ToTextノードは詳細設定ができます。

f:id:hiyokosabrey:20190310200846p:plain

Minimum Fractional Digits を 1 にすると、キリのいい値のときでも、0 を表示するようになります。

 

これでWidgetの編集は完了です。

コンパイルして閉じます。

 

次は、このWidgetに距離を調べて渡す部分。

レベルブループリントを編集します。

すでにつないである部分2つ目の Create Widget のReturn Value ピンで右クリックします。

f:id:hiyokosabrey:20190310205114p:plain

Remote To Variable (変数へ昇格)を選択して、変数化します。

f:id:hiyokosabrey:20190310205410p:plain

これに名前を付けて、間に挟み込みます。

f:id:hiyokosabrey:20190310205521p:plain

この操作で、追随するWidgetに対してアクセスが可能になります。

 

これをEventTickで使用します。

f:id:hiyokosabrey:20190310210459p:plain

対象の3Dオブジェクトと、プレイヤーカメラの距離を表示してみます。

双方のポジションを取得して引き算すると差分が得られます。それを VectorLength ノードが距離として返してくれるので、これを利用します。

 

 最初3次元上の2点の距離を調べる公式を使ってノードを組んでいたのですが、

f:id:hiyokosabrey:20190310212922p:plain

f:id:hiyokosabrey:20190310212023p:plain

ブループリントで数式を組むとなんだか不思議な感じがするのは気のせい?

 

検証している途中でステキな記事を見つけたので、シンプルな VectorLength を使った形に変えました。

qiita.com

 

 これで完成です。

 

 再生して確認してみると、

f:id:hiyokosabrey:20190310211607g:plain

ここまで来たらあとは見た目をゴニョゴニョするだけですね。

 

 

いかがだったでしょうか?

実際に組み込もうとすると、もっと機能性や汎用性を持たせた方がいいと思いますが、ゲームメカニクス次第なところもあってこれ以上は踏み込むのは難しいかな。

とはいえ結構個人的に面白いネタだと思うので、もう少し遊んでみようと考えています。

分かりにくいとことかあれば↓コメントかツイッターで質問OKです。

 

こんこんと泉のごとく沸き続ける鼻水と目のかゆみと闘いながら変なテンションで書いています。

いちいち眼鏡外さなくてもさりげなく点眼する方法って開発されないかな。

 

ではでは

ステキなマーカーライフを!

3Dオブジェクトの上にWidgetをマーカーのように表示する。画面外にいっても大丈夫。操作手順もできるだけ丁寧に書いてみたけどどうかな?

前回の更新からちょっと間が空きましたが、ぷちコン作品を作ってました。

で、先日とあるツイートに目がとまったのです。

 

 

 これは、Worldに存在する Actor の上に Widget を表示するという内容で、さらに対象の Actor が画面外に出ても、画面の端に張り付くようにするという 素晴らしいものです。

 3Dオブジェクトの上にWidgetを表示するという方法は、すでにブログ等で公開されているので、目新しさは無いですが、画面の外に出ないようにする工夫に心惹かれました。

  ツイ主の @ghosticgames さんにブログで説明してもよいかコメントで確認したら、"Sure! "(もちろん!)という返事を頂けたので、さっそく当ブログで説明させていただくことにしたわけです。質問箱からもブログのネタにどうかという提案(いい感じに解釈)もあってこれはもうやってやるしかないなと。

 

 

まずは、さっそくツイート画像を見ながら全く同じように試してみました。

その結果がこちら。

 (このツイート、「メディア」にはログとして残ってるけど「ツイート」には出てこなくなった・・・)

 

 基本的な原理はとてもシンプルです。さっそく他の方法はないかとアレコレ実験してみたんだけど、扱い方次第になると思うので、今回は手を加えずに教材として説明してみます。

 

 ツイートされてる画像とレイアウトや変数名などが若干違うものがありますが、基本のロジックは同じ構造です。基本的な動作を作った後でアレンジとして対象までの距離を表示するとこまでやろうと思います。

f:id:hiyokosabrey:20190306231002j:plain

今回はUMGやブループリント編集に慣れていない方でも作れるように操作方法をなるべく細かく書くようにしてみました。(作業の能率がいいので英語環境をオススメします)

 

 

 

用意するWidgetは2つ。

f:id:hiyokosabrey:20190306231618p:plain

 まずは1つ目のWidgetから

 

キャンバスだけのWidget

コンテンツブラウザから、 右クリック > User InterfaceWidget Blueprint

で作成できます。

 

できたらダブルクリックしてエディタを開きます。

エディタウィンドウ左にある、Hierarchy タブの中を確認すると、あらかじめ Canvas Panel_0 というのが置かれているので、クリックして選択。

f:id:hiyokosabrey:20190306233841p:plain


続いて右上の Is Variable というチェックボックスにチェックを付けます。

f:id:hiyokosabrey:20190306233045p:plain

付けることで、ブループリントからこの CanvasPanel_0 に対して直接いじることができるようになります。キャンバスパネル は UIパーツを描画するため使われます。

 

念のためキャンバスの描画サイズを確認。

f:id:hiyokosabrey:20190306234311p:plain

これはこのWidgetを、画面いっぱいまで使って描くよ、という意味合いです。

 

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

コンパイルして保存したら閉じてもOK.

f:id:hiyokosabrey:20190307002412p:plain

 

 

 

次は2つ目のWidget

 

Actorをフォロー(追随)するWidget

今度はキャンバスのサイズを指定します。

f:id:hiyokosabrey:20190307003540p:plain

Fill Screen と書かれている部分は、プルダウンメニューになっているので、Custom を選択します。

幅(Width)と高さ(Height)を指定できるようになるので表示したい適当なサイズ(単位はピクセル)を入力します。今回は100x100で作りました。

f:id:hiyokosabrey:20190307003734p:plain

 

次にキャンバスに、2つのパーツ Image と TextBlock を配置します。まずは Hierarchyパネル で ドラッグ&ドロップします。

f:id:hiyokosabrey:20190307004520p:plain

ドロップしたら、エディタウィンドウ右のDetails パネルで設定をいじっていきます。

 

 Image の方から。

Anchor(アンカー)はそのままでOK。

f:id:hiyokosabrey:20190307223852p:plain

キャンバスの中めいっぱいになるように、Sizeをキャンバスの大きさと同じ値を入力します。

あとは Detailsタブの Appearance > Tint で好きなカラーをセットしたら下敷きは完成。

 

次にTextBlock。

こちらもAnchorを設定します。

f:id:hiyokosabrey:20190307221700p:plain

中央揃えにしたいので、『Top-Center(勝手に命名)』 を選択。

パラメータは以下。

f:id:hiyokosabrey:20190307222529p:plain

テキストのカラーと文字サイズを決めて、レイアウトをセンタリングにします。

f:id:hiyokosabrey:20190307222916p:plain

あと、これもブループリントから内容を書き換えるので、Is Variable にチェックを付けておきます。

 

キャンバスがこんな感じになればOK。

f:id:hiyokosabrey:20190307222732p:plain

 

いよいよブループリントを編集します。

編集モードを切り替えます。

f:id:hiyokosabrey:20190307224355p:plain

 

切り替わったら、グラフの何もない所で、右クリックします。

f:id:hiyokosabrey:20190307224712p:plain

Add Custom Event を探します。Search のところで検索ワードを入力するか、一番上にAdd Event というカテゴリを開くと見つかります。(←英語環境)

見つけて選択するとノードが現れるので、

f:id:hiyokosabrey:20190307224914p:plain

InitFancyFollowingWidget と名付けておきます。

ここにパラメータを受け取るための 入力ピン を追加します。

このノードを選択したまま(オレンジの枠線をつけた状態)Detailsタブを見てみるとInputs という項目があるので、右にある + ボタンを 静かに2回クリック。

f:id:hiyokosabrey:20190307225733p:plain

適当な型の設定項目が2つ並ぶので、上からプルダウンを開けて、

Actor を探します。

f:id:hiyokosabrey:20190307230610p:plain

2つ目は

Canvas Panel Slotを探して選択します。

f:id:hiyokosabrey:20190307230832p:plain

下のようになればOK。

f:id:hiyokosabrey:20190307225945p:plain

PINの目的(役割)を後から思い出せるように、それぞれに名前を付けておきます。

これでグラフに置いたノードが変化します。

f:id:hiyokosabrey:20190307231151p:plain

次は変数を用意します。この青いピンからドラッグして作成します。

f:id:hiyokosabrey:20190307232229p:plainPromote to variable(変数へ昇格)を選ぶと、ピンと同じ型の変数が、SETノードの形で現れます。

f:id:hiyokosabrey:20190307232352p:plain

名前を付け直したら、2つ目のピンも同じようにして変数化します。

f:id:hiyokosabrey:20190307232719p:plain

これで、ターゲットとなる Actor と配置用の キャンバスパネルスロット にアクセスするための準備ができました。まだこの時点では中身はなくて空っぽな状態です。型が決まった器があるだけです。

変数化できたので、エディタウィンドウ左にある、Variables のリストに追加されているのが確認できます。そこから、グラフにノードとして取り出します。

f:id:hiyokosabrey:20190307235600p:plain

Ctrlキーを押しながらドロップすると、いきなり GET のカタチで取り出せます。

ちなみに Altキーだと、SETのカタチで取り出せます。

 

このノードの中身が入っているか確認してから処理するので、確認用のノード is Valid をつなぎます。

f:id:hiyokosabrey:20190308000317p:plain

なんらかの不具合や処理順などで受け取りを失敗することがあります。その時は中身が無効になることがあるので、このノードでチェックするのが安全です。今回は 両方が有効の場合のみ 処理したいのでAND(Boorean)を使います。これは論理式というやつで『 A かつ B 』という意味になります。両方のIsValid ノードの結果が true になってようやく true になります。

これらを、グラフに最初から置かれている赤いイベントノード、Event Tick ノードにつなぎます。

f:id:hiyokosabrey:20190308000109p:plain

 

右端は、表示位置をセットするノードです。変数CanvasSlotをもう一つGETで取り出すと、そこから安全に取り出せます。

f:id:hiyokosabrey:20190308001627p:plain

f:id:hiyokosabrey:20190308001745p:plain

仕上げに、ポジションを計算する関数を用意します。

今回の要の部分です。

 

座標計算用の関数

MyBlueprintタブの Functions のところにある +ボタンをクリックして新しい関数を準備していきます。

f:id:hiyokosabrey:20190308002405p:plain

 名前を ProjectWorldToScreenClamed としておきます。

f:id:hiyokosabrey:20190308231337p:plain

グラフが切り替わっているので、ノードをつないでいきます。ちょっと長めです。

 

まず、①Get Player Controller 、そのReturn Value からは、②Get Viewport Size

f:id:hiyokosabrey:20190308232618p:plain

 右にある2つの変数は ローカル変数です。この関数内だけという限定された範囲で使うためのものです。関数の外では利用できない変数です。別の見方をするとこの関数以外での利用価値が無い、とも言えます。今回一時的な計算のためだけに存在するのでローカル変数を使用します。

 作り方は、Get Viewport Size ノードの SizeX と SizeY のピンからドラッグ&ドロップするとポップアップメニューが出るので Promote to Local variable を選択すると簡単です。

f:id:hiyokosabrey:20190308233407p:plain

  エディタ左の MyBlueprintタブに、関数を編集している時にだけ現れる Local Variables であらかじめ用意しておくこともできます。

f:id:hiyokosabrey:20190308233822p:plain

ドラッグして作る方が、VariableType(変数の型)が確実に設定されるのでオススメ。

 

まず Viewport の大きさ(画面表示サイズ)を変数に入れておきます。

 

 

今度はこのWidgetのキャンバスに置いたパーツのサイズを取得して、これもローカル変数に取り置きします。

f:id:hiyokosabrey:20190309105044p:plain

 

まず①Get a reference to self ノードから始めます。

f:id:hiyokosabrey:20190309001902p:plain

Get Desired Size表示しようとしているサイズを返します。Self(自身)に対してつないでいるので、キャンバスに配置したすべてのパーツを含めた最終的な表示サイズのことを指します。

③は vector2d と Float を掛け算するノードです。ドラッグ&ドロップして  *アスタリスク)で検索すると見つかります。

f:id:hiyokosabrey:20190309002428p:plain

 

④Get Viewport Scale は、ディスプレイ解像度を 1 として、UE4実行時に実際に表示されているウィンドウの表示倍率を返してくれます。

f:id:hiyokosabrey:20190309105223p:plain

ディスプレイの解像度設定は公式ドキュメントにあるように設定ファイル "GameUserSettings.ini" に書かれています。

 

⑥は 複数の型で構成されているVector系のデータを分解してくれるノードです。Vector2D 型 は Float型のデータを2つ束ねています。主に XY座標を扱う場合などで使います。

⑦と⑧は これも ローカル変数に格納します。

 

 

 まだまだ続きます。

これはワールドにあるアクターの座標をScreen座標に変換します。

f:id:hiyokosabrey:20190309113742p:plain

 用意しておいたカスタムイベント InitFancyFollowWidgetで受け取っている変数オブジェクトを変数リストからドラッグ&ドロップして始めます。

f:id:hiyokosabrey:20190309114328p:plain

そこから② Get Actor Location でアクターのワールド座標を取得 → ちょっとだけ位置をずらします。

ConvertWorldLocationToScreenLocation というノードで、3次元のワールド座標を画面で見ている2次元のスクリーン座標に変換します。このノードは、先にGet Player Controller ノードを取り出しておくとスムーズに取り出せます。④→⑤

ここにアクターのポジションを渡してやります。

これをまたローカル変数に取り置きします。⑧、⑨

 

右端のは Returnノードです。 関数には基本このリターンノードを置きます。関数というからには何かしら計算や処理した結果があるので、この Return ノードから、外に出してやるのです。ノード検索キーワードに ピリオド 「 . 」 を入力するとすぐ見つかります。

このリターンノードには アウトプット用のピンを追加できます。リターンノードを選択して、Detailsタブから追加します。

f:id:hiyokosabrey:20190309120515p:plain

 

このリターンノードで返す値がこちら。

f:id:hiyokosabrey:20190309121102p:plain

取り置きしてきた座標やサイズの値をここで一気に計算します。

上段が X座標、下段がY座標用です。それぞれ Clampノードではみだしをカットしています。今回の一番重要な処理だと思います。

Integer型 と Float型 の引き算はそのままではできないので、Integer型をFloat型にキャスト(型変換)してやります。

ノード検索で「 to 」と入力すると ToFloat(Integer) が選択できます。

f:id:hiyokosabrey:20190309122206p:plain

こんなノードが出てきます。

f:id:hiyokosabrey:20190309122432p:plain

全体図はこんな感じ。

f:id:hiyokosabrey:20190309122909p:plain

@ghosticgamesさんのと同じ内容ですが、説明用にコンパクトにしました。

 

これで関数は完成ですが、最後の仕上げとして、この関数をPure型にします。

f:id:hiyokosabrey:20190309125648p:plain

Pureにチェックを付けると・・・

f:id:hiyokosabrey:20190309130113p:plain

グラフにノードとして取り出した際に、実行ピン(白色)がない状態になります。

これを途中だった EventTick処理につないだら完成です。

f:id:hiyokosabrey:20190309130359p:plain

コンパイルして保存したらと閉じてもOK。

 

表示を確認してみる

ワールドに適当なオブジェクトを配置します。

f:id:hiyokosabrey:20190309131522j:plain

実験では、Transformを持ってさえいれば動作すると思います。

配置できたら、手っ取り早いのでレベルブループリントを使って確認します。

 

レベルブループリントの編集方法はこちらから。

f:id:hiyokosabrey:20190309131921j:plain

グラフ編集エディタが開きます。

 ①Create Widget からつないでいきます。

f:id:hiyokosabrey:20190309173918p:plain

アクターに追随するWidgetは、Viewort に追加せずに、先にAdd to Viewport したキャンバスだけのWidget内に持っている CanvasPanel の子供にします。

さらに続き、

f:id:hiyokosabrey:20190309174710p:plain

スムーズにつなげるコツは、白い線は気にせずに、Return Value からドラッグして検索することです。つながるのが約束されているノードが取り出せるので安心です。

 

⑧Set Auto Sizeノードは Inb Auto Size にチェックを付けておきます。

 

⑩はワールドに置いたオブジェクトをドラッグします。
f:id:hiyokosabrey:20190309180355p:plain

この方法は可能なブループリントが限られます。

 

これですべての準備は整いました。

再生してみましょう。適当にカメラを動かしてみてください。

f:id:hiyokosabrey:20190309182035j:plain

対象のオブジェクトが画面から消えても残り続けます。

f:id:hiyokosabrey:20190309182308j:plain

これが Clampを使った移動制限です。

 

一応動画のURLを貼っておきます。

みつまめ杏仁Ver

@ghosticgames さん版

 

細かくオペレーションを書いていたら思ったより長くなってしまいましたが、今回はこの辺まででいったん筆を置こうと思います。

 

次回、計算の仕組みを軽く解説して、オマケの「距離」を表示する部分を書きます。

@ghosticgames さん ステキな教材をありがとう。

 

ではでは

ステキなターゲット表示ライフを!











 

 

 

UMGパーティクル(なんちゃって)

 Widgetでパーティクルっぽいやつを作ったのでTwitter動画をあげたら、いいねしてもらえたので記事にしてみます。さくっとParticleをWidgetに乗せる方法が見つけられなかったのでUMGで作ってみた次第です。

 

変数の型に Box2Dというのがありまして、

f:id:hiyokosabrey:20190214223938p:plain

これを配列にして管理したらいいんじゃね?ってなったのが作り始めたきっかけ。

 

BoxなんでRectangle(長方形)の4頂点のうちの対角の2点を扱うための型です。

f:id:hiyokosabrey:20190214224414p:plain

2D座標ということで xとy を扱うVector2D が2つ束ねられているかたちです。

f:id:hiyokosabrey:20190214225611p:plain

今回これをFloat型が4つあるという認識で扱うことにしました。

 

 ちなみに 他に (x, y, z)の Vector型で2点をまとめた Box型や、BoxSphereBounds型というのもあるようです。ピンの色的にStructure(構造体)の類ですよね。

 

 

パーティクル用に格納する値は3つ。最終回転角と目的地の座標です。

f:id:hiyokosabrey:20190214230317p:plain

ここに粒ごとのゴール位置と何回転するかの値を入れていきます。

 

f:id:hiyokosabrey:20190214231111p:plain

Construct Object From Classノードで WidgetImage を量産して配列に格納。ついでにパーティクルのパラメータを設定。右端のマクロの中身はこんな感じ。

f:id:hiyokosabrey:20190214235115p:plain

発生源から ±500(50.0刻み)の範囲がゴール位置。±3 ~ ±7 回転。

 

次にキャンバスに追加。

f:id:hiyokosabrey:20190215001327p:plain

OffsetPos と、 Color はこのパーティクルWidgetを呼び出すやつがセットするので、受け取るための設定をします。

f:id:hiyokosabrey:20190215001805p:plain

 

パーティクルが発生してから、2秒後に消滅するようにタイマーをセット。Tickのためのフラグを立てて、フェードアニメーションを呼び出します。

f:id:hiyokosabrey:20190215002438p:plain

フェードアニメーションは、キャンバスに対して Render Oapicty を 1.0 → 0.0 にすることでパーティクルを一斉に消します。

 

移動処理のTickは以下。

f:id:hiyokosabrey:20190215003255p:plain

一粒ずつ処理します。ポジションと回転は、WidgetのRenderTransform を使います。それぞれの更新に必要な計算はマクロでやってます。

 

getNewTranslation

f:id:hiyokosabrey:20190215003916p:plain

 

getNewAngle

f:id:hiyokosabrey:20190215004142p:plain

 

これでパーティクルのWidgetは完成。

あとは呼び出すだけ。

 

クリックしてヒットしたときの処理に追加します。

f:id:hiyokosabrey:20190215004931p:plain

パーティクルのカラーは数字の色同様に、あらかじめ配列で持っておきます。

f:id:hiyokosabrey:20190215005102p:plain

 

できあがりです。

f:id:hiyokosabrey:20190215010157g:plain

 

一応動画を確認するためのツイートを貼っておきます。

 

パラメータを工夫すると散り加減が変えられたりして楽しめます。

テクスチャを貼るとまた違った印象になると思います。

 

 

ではでは

 今回はこの辺で

 

ステキなUMGパーティクルライフを!

 

クリックするだけの簡単なゲーム 《改造編》

さっそく前回作ったやつを改造していこうと思います。

 

limesode.hatenablog.com

 

改造ポイントは4つ。

  1. 繰り返し遊べるようにする
  2. タイマーのガクガク震えるのをなんとかする
  3. ちょっと難易度を上げてみる
  4. おまけ

 

まずは、クリアしたあとにボタンを表示したいので、キャンバスにButtonを追加します。作り方は開始時の Click To Start ボタンと同じ作りでいきます。

f:id:hiyokosabrey:20190211142709p:plain

配置したら、Visibility を Collapsed にして非表示にしておきます。

f:id:hiyokosabrey:20190211143238p:plain

 

このボタンを表示する処理をクリア時の処理に追加します。

f:id:hiyokosabrey:20190211144125p:plain

ボタンが表示された次は、ボタンがクリックされた際の処理です。

エディタの Variables の欄に、Buttonが追加されているので選択して Details タブを更新します。

Events の項目に On Clicked があるのでクリックしてイベントノードを取り出します。

f:id:hiyokosabrey:20190211144558p:plain

イベントノードを取り出したら、ひとまずボタンは用済みなので再び非表示に戻してやります。合わせて Complete! の文字も消します。

f:id:hiyokosabrey:20190211150238p:plain

 この後、いろいろと初期化と再セットをしていくのですが、一旦寄り道して、タイマーの改造を進めます。とはいえちょっとブループリントが賑やかになってきたので、改造というよりは新しくタイマー用のWidgetを作ることにします。

 

 いつものようにキャンバスにパーツを配置していくのですが、Epicがストアで無料で提供してくれているプロジェクトを見ていて最近学習した方法があるのでそれでいきます。今頃ですが・・・

 キャンバスのサイズはでデフォルトだと 1080pだったりしてPC環境やコンソールのゲーム機だとそのままで良かったりで、あまり気にしてなかったのですが、Widgetで部品パーツを作る際はなんかもったいないような気がしてました。

f:id:hiyokosabrey:20190211151559p:plain

この右上の Fill Screen を 変更できることができます。

固定サイズなら、Custom、 中身次第にするなら Desired に切り替えるだけ。

f:id:hiyokosabrey:20190211151714p:plain

タイマーはデジタル的に表示したいのでTextBlockをキャンバスパネルの子供にして表示桁ぶん並べます。

f:id:hiyokosabrey:20190211152006p:plain

Desired にしていると キャンバスのサイズは自動的に合わせられます。

ピリオド以外は Is Variable のチェックを付けておきます。

f:id:hiyokosabrey:20190211152240p:plain

 

ブループリントを編集します。

小数点の値を受け取って桁を分解してテキストを更新する関数を用意します。

f:id:hiyokosabrey:20190211153322p:plain

桁の分解は、小数点の扱いがポイントになります。Fraction で整数部分を、Floor で小数以下を切り捨てることで、小数点を境界にして大きく2つに分けることができます。 あとはそれぞれで整数にして計算します。

図で解説してる過去記事を貼っておきます。

limesode.hatenablog.com

これで、数字の文字幅によるブルブルがなくなります。

f:id:hiyokosabrey:20190211154907g:plain

この関数は外から呼ばれますが、初期値のセットも兼ねて、グラフにつないでおきます。

f:id:hiyokosabrey:20190211154354p:plain

タイマーは完成。

 

メインのWidgetに戻って、配置します。

もとのTextBlockで簡易的に作ったタイマーをこのWidgetに差し替えます。

f:id:hiyokosabrey:20190211201015p:plain

中央揃えの場合、Size To Content にチェックを付けるとレイアウトしやすいです。

タイマーの更新処理のところも、このWidgetの関数に置き換えます。

f:id:hiyokosabrey:20190211222746p:plain

100以上の桁表示を作っていないので、99.99カンストするようにしています。表示は見た目に止まりますが変数へのカウントアップは止めていないので、必要であればもう一つフラグを用意した方がよいかも。数字の桁を足す場合、 000.00 となるので、ゼロサプレスの処理が欲しくなる。この辺りは、ランキングの仕組みや、100秒を上回るのが当たり前のような難易度かどうかなどを考えると決まってくると思います。

 

で、寄り道で中断していたRetryボタンの処理の続きです。

f:id:hiyokosabrey:20190211203237p:plain

変数を初期値に戻します。このあと難易度を上げるところで理由を書きますが、ここで StepCount の値を 1始まりではなく 0 にします。

 

あとは、出現イベントから始めれば、通常のゲームループに戻れるはずです。

そのためのカスタムイベントを作って、出現処理のところに脇からつなぎます。

f:id:hiyokosabrey:20190211203936p:plain

 

このカスタムイベントを呼び出すのが、さきほどの ForEachLoop処理の Completeピンです。

f:id:hiyokosabrey:20190211204204p:plain

 

これで大体できました。仕上げに難易度を上げる処理です。

 

その準備として、Integer型の配列変数をもう一つ追加します。

f:id:hiyokosabrey:20190211204532p:plain

次に、先に作っていた NumberPool という Int型の配列も少し初期化の部分を変更します。Event Pre Construct の部分に、配列のサイズを設定するノードを挿入。

f:id:hiyokosabrey:20190211204931p:plain

数字を初期化する関数を改造します。

 

まず、前回と同じく 1~25 までの数字で遊ぶ場合。

f:id:hiyokosabrey:20190211225827p:plain
 先に配列のサイズを決めているので、ここでは Addノードは使えません。代わりにSet Array Elem という、指定した 場所の内容を書き変えるノードを使います。

 今回新しく追加したチェックのための配列をクリアしてから、シャッフルする前の状態を保存しておきます。このクリアは、すぐあとのコピーのために行っていて繰り返し遊ぶときに重要になります。上のようなシンプルなパターンでは、効果が薄いのですが、効果を発揮するのが次のパターン。

 

 もっと難しくする場合。

f:id:hiyokosabrey:20190211225802p:plain
 1~99 までの 25個の数字で遊びます。まんべん無く数字が使われるようにしたかったので25枚目のやつだけループ処理が終わってから乱数をセットしています。

 

 このパターンだと1~25のように パネルの番号とクリックの順番が一致しなくなるので、チェックしやすくするためシャッフルする前の状態が必要になります。

 そこで、チェックのところが、下のように変わります。

f:id:hiyokosabrey:20190211211051p:plain

配列から値を順番に0から取り出してチェックしてゆくので、変数StepCountをゼロ始まりに変更しています。

 

これで改造ポイント1~3完了です。

再生して数字の並びを確認してみます。

f:id:hiyokosabrey:20190211211323p:plain

一番小さい数字からクリックしていくのですが、これが結構難しくて、なかなか30秒切れなかった。

 

youtu.be

 

ここからはおまけです。

 

 上に貼った動画ですでに入ってますが、マウスのホバー処理とエフェクトを出してみます。

 クリックしたときにエフェクトを出せないかと実験してみたけど、ParticleSysytemは、Screen描画してるWidgetよりも手前に描画できないようなので、とりあえず数字がヒットしたタイミングでプリセットの爆発エフェクトをSpawn してみたら派手で面白かったのでそのまま動画を撮りました。

Spawn Emitter at Locationを一つ追加するだけ。(雑い・・・)

f:id:hiyokosabrey:20190212031548p:plain

 再生時のカメラの視界に入るように座標を調整してるだけ。カメラが動くと当然ズレますが何か? WidgetをWorldに置くか、エフェクトをRenderTargetTextureにしてWidgetで利用するしかない感じ?

 

 

 次はホバーエフェクト。当然タッチオペレーションだと無意味なやつです。マウスオペレーションならではですね。動画キャプチャにマウスカーソルが写り込まないので作ってみました。

 そのための仕込みとして、色を付けるための Image をキャンバスに追加します。

f:id:hiyokosabrey:20190212032926p:plain

 カラーは数字の色に合わせて5色用意したいのですが、カラーごとにアニメーションを作るのはナンセンス。というわけで間に1枚専用のパーツを追加して、Render Opacity でアニメーションさせよう、って腹です。カラーは数字の色と同様に配列を用意します。型はLinearColor型。

f:id:hiyokosabrey:20190212201636p:plain

(Font は SlateColor なのは何か理由があるのかな?地味に不便な気がする。)

 

この配列からカラーを取り出してセットする処理を 数字を受け取る関数に追加します。

f:id:hiyokosabrey:20190212202123p:plain

 

このあと、マウスカーソルが乗った時、離れた時、のイベントを用意するのですが、その前に、マウスカーソルが離れたとき用のアニメーションを作っておきます。

f:id:hiyokosabrey:20190212204021g:plain

 RenderOpacity が追加されたことで、Colorのフェードを触らなくていいのが嬉しいです。この RenderOpacity の初期値は 0.0 にしておきます。

 

あとは、マウスイベントをOverrideします。

f:id:hiyokosabrey:20190212204317p:plain

長いプルダウンリストから、 On Mouse EnterOn Mouse Leave を選択します。

 

On Mouse Leave は自身の上にマウスカーソルが乗ってる状態から、離れた瞬間に呼び出されるイベントです。

f:id:hiyokosabrey:20190212205626p:plain

ただ再生するだけでOK。

 

一方、On Mouse Enter は自身の上に マウスカーソルが乗った(入った)瞬間に呼び出されるイベントです。ここでようやく Render Opacity が 1.0 になります。

f:id:hiyokosabrey:20190212205940p:plain

このイベントが呼び出されたときに、アニメーションが残っている可能性があるので、強制的に止めるようにしています。

 これで、カーソルが乗った瞬間に Render Opacity が 1.0 になって、カーソルがはなれたら、0.0に向かってアニメーションするようになります。

 

このくらいでいいかな~と思ったのですが、もう一つ思いついたので作ってみました。

数字の配列を作る関数をちょっといじります。

f:id:hiyokosabrey:20190212212543p:plain

0~25までの 26個の数字を配列に入れるのですが、25個までと決めてあるので、この関数内だけで使えるローカル変数を使います。

f:id:hiyokosabrey:20190212212818p:plain

26個の数字から、一つだけランダムで抜いて25個したら完成です。

 

次に、数字パネルのWidgetに手を加えます。

こんなマクロを用意します。

f:id:hiyokosabrey:20190212213455p:plain

 もうお分かりですね。アルファベットバージョンです。

 しかも、大文字小文字が混在です。A~Z 26文字のうち、1文字だけ足りないので、ジジ抜きのような微妙な緊張感も一緒に楽しめるというやつです。

 

で、このマクロを無理やり↓挿しこみます。

f:id:hiyokosabrey:20190212213855p:plain

どんな感じかというと、

f:id:hiyokosabrey:20190212214114p:plain

ほどよい難易度でなかなか新鮮です。

 

 

 いかがだったでしょうか。ひとまず今回の改造はここまでにしておきます。

 始まりから終わりまで一つのゲームルールができると、いろいろアイデアも出やすい気がします。リザルト画面とかランキングとかネームエントリーとか作ると、どんどんアプリっぽくなっていきそうです。お手付きをカウントしたり一定の間隔以内だったらコンボボーナスとか。一定時間ごとに「急いで!」とか急かしてみたり。ヒント的にパネルが揺れたりしてもいいかもしれない。ベルトコンベアになってても面白そう。もうルールを変えて、何らかのペアをクリックして消しいくのもいいかもしれない。

 イマドキのUE4のトレンドとは逆行してる気がしないではないけど、まぁ楽しんで作れるのが何よりも一番大事だと思う。

 

 

ではでは

ステキはパネルクリックライフを!

 

 

 

クリックするだけの簡単なゲーム

 前回の記事で、パラパラとパネルを出現させるやつで遊んでたら、ビンゴカード ぽい見た目になったりしたので、さらに調子に乗ってミニゲームにしてみた。もう10年以上前?かな、一度流行ったことがあって、それの再現です。

f:id:hiyokosabrey:20190209210630j:plain

 ルールは、1~25までの数字が書かれたパネルを、順にクリックして全部クリックするまでにかかった時間を競うというものです。あぁ アレか・・・という溜息が聞こえてきそうですが、わりと手軽?に作れたので記事にしてみようかと。ただ記事的にちょっとボリュームがあるかも・・・

 

 作りはシンプルにいきます。作るWidgetは2つだけ。

 

まずは1個目のWidget。キャンバスから。

ここに 120x120の CanvasPanel を一つ。

f:id:hiyokosabrey:20190204001027p:plain

このキャンバスに対して、Image(下敷き) と TextBlock(数字)、Image(カバー用)を子供に します。

f:id:hiyokosabrey:20190204001340p:plain

ここまでは前回と同じ。

このパーツたちに対してアニメーションを用意します。

今回用意したのは以下の4つ。

 

FADE_IN

f:id:hiyokosabrey:20190207003101g:plain

最初の出現用です。この時点で数字はわかりません。

 

 

COVER_OUT

f:id:hiyokosabrey:20190207003403g:plain

ゲーム開始時に 上の FADE_IN 再生後の状態から続く感じで再生します。インパクトを出すために青いカバーを白くします。

 このタイミングで数字と下敷きを表示するのですが、ちょっとだけ仕込みが必要。

f:id:hiyokosabrey:20190209134302p:plain

このあと数字を拡大して消すときに、隣のWidgetにかぶさるとクリック判定を邪魔してしまうのを防ぐために、TextBlockだけは Hit Test Invisible を選択します。

 

 

REMOVE_PANEL

f:id:hiyokosabrey:20190207003933g:plain

クリックして順番が正解した際の演出です。数字だけを消しています。

 

 

FADE_OUT

f:id:hiyokosabrey:20190207004216g:plain

全てのパネルを消した後の演出です。

 

キャンバスはここまで。

次はWidgetブループリント。

 

まずは変数を4つほど用意。

f:id:hiyokosabrey:20190209131348p:plain

 

ちょっと色気を出すためにSlateColor型の変数を配列にします。

f:id:hiyokosabrey:20190207213121p:plain

適当に5色をセット。

 

次に値を受け取る関数を用意します。

f:id:hiyokosabrey:20190207213533p:plain

Integer型のInputピンを2つ。受け取った値は、後で別の場所でも利用するので、すぐに用意しておいた変数にお取り置きします。Indexはパネルの場所を表す値。左上が0、右下が24です。

f:id:hiyokosabrey:20190205002714p:plain

このIndex番号を %5(5で割った余り) すると、下のようになります。

f:id:hiyokosabrey:20190205003147p:plain

この計算した数値をフォントの文字カラーとして配列から引っぱり出しすと左の列から順に色が変化することになります。

 

Numberは表示するための数字です。

 

関数の次は、イベントディスパッチャーを2つ用意します。

f:id:hiyokosabrey:20190207214725p:plain

アニメーションの終了通知と、クリックされた際の応答に使うためです。

応答用のは、値を送り返すのでInputピンを2つ追加します。

f:id:hiyokosabrey:20190207214939p:plain

 

アニメーションを再生するためのカスタムイベントを用意していきます。

最初の登場演出用。

f:id:hiyokosabrey:20190209132003p:plain

出現時、まだクリックを受け付けたくないので、フラグを False にしておきます。

※このフラグは後述のマウスイベントの処理のところで活躍します。

 

このアニメーションの後に、『 Click to Start 』って出したいのでアニメーション終了通知のために、イベントディスパッチャーを呼び出し(Call)ています。

このWidgetは画面に 25個も表示するので、通知処理は最後の1個だけで十分です。前の24個は通知処理しなくてもいいので、カスタムイベントのInputピンにBooleanを一つ追加しています。

ちなみに、このイベントを呼び出す際は下のようなノードになります。

f:id:hiyokosabrey:20190207222535p:plain

 

次は、ゲーム開始のための表示演出イベント。

f:id:hiyokosabrey:20190209134805p:plain

ここから、マウスクリックを受け付けるので、フラグを True にします。

 

次は、数字がヒットして、消えるときの表示演出イベント。

f:id:hiyokosabrey:20190209135301p:plain
ここで マウスクリックを受け付けたくないのでフラグを False にします。

 

 

次のイベントは、ゲーム終了時の表示演出イベント。

f:id:hiyokosabrey:20190207224027p:plain

 

これで4つのアニメーション再生の準備は整いました。

 

最後に、マウスクリック時の処理を用意します。

関数を作るところに Override ボタンがあるのでそこから

f:id:hiyokosabrey:20190207224936p:plain

On Mouse Button Down を選択してから編集します。

f:id:hiyokosabrey:20190209140223p:plain

 クリック受付するかしないかのフラグをみて分岐させます。

 

これでパネル用Widgetが用意できました。

 

メインになる親のWidgetを用意します。

キャンバスには パネルを並べるための WrapBoxを一つ。

f:id:hiyokosabrey:20190207231937p:plain

中央になるように調整します。

f:id:hiyokosabrey:20190207231820p:plain

f:id:hiyokosabrey:20190207233215p:plain

パネル1枚が 120x120なので、 120x5 + スキマ から指定幅を計算。指定幅を越えたら改行するので、6個目が並ばないように指定します。

Size To Content にチェック付けると、 Size XとSize Y は無意味なので初期値でOK。

 

次に、タイマー用の TextBlockを配置します。

f:id:hiyokosabrey:20190207234327p:plain

とりあえず、WrapBoxのすぐ上あたりに。

次は、クリアしたときの「 Complete! 」をTextBlockで配置。

f:id:hiyokosabrey:20190207234608p:plain

これはクリアしたときまで取っておくので、配置したらVisibilityの設定を非表示(Collapsed)にしておきます。

 

あとは、Click To Start のボタンを配置します。

f:id:hiyokosabrey:20190208002547p:plain

覆うように大きく大胆に広げます。

f:id:hiyokosabrey:20190208002557p:plain

配置したButtonの子供にTextBlockを置くと、中にテキストを置けます。

Hierarchyはこんな感じ。

f:id:hiyokosabrey:20190208003031p:plain

f:id:hiyokosabrey:20190208003505p:plain

 

このままだと後ろが見えないので、Buttonのカラーをカスタマイズします。

とりあえずカラーは 黒 でアルファが 0.5 くらいにします。

Buttonコンポーネントは専用のイベントをいくつか持っているので、Normal、Hovered、Pressed の3か所を触ります。

f:id:hiyokosabrey:20190208004043p:plain

あくまでもボタンの地の色で、テキストブロックのカラーは変化しません。

f:id:hiyokosabrey:20190208220346p:plain

Buttonを大きくするのは、数字のパネルがクリックを受け付けてしまうのを防ぐ目的もあります。

 

キャンバスはこの辺にして、ブループリントを編集します。

 

まずは、数字を配列にセットする関数。

f:id:hiyokosabrey:20190208220655p:plain

配列のIndex番号は 0(ゼロ)始まりだけど、ゲームの表示は 1(イチ)からなので、ForLoopを使って、1~25 の数字を格納。

 

配列をシャッフルする関数。

f:id:hiyokosabrey:20190208220917p:plain

配列にShuffleノードをつなぐだけで配列の中身をシャッフルしてくれます。

 

上の2つの関数を Event Pre Construct につないでおきます。

f:id:hiyokosabrey:20190208223307p:plain

クリックしたパネルの数字が順番通りかどうかチェックするための変数もここで初期値をセットしておきます。

このイベントは 、ブループリントをコンパイルした時点で一度処理されるという特殊仕様です。結構便利な使い方ができるので後ほどご紹介します。

 

次は数字パネルのWidgetを並べる処理。

f:id:hiyokosabrey:20190208225251p:plain

真ん中付近の配列の作り方は、

f:id:hiyokosabrey:20190208225442p:plain

Create Widget ノードの ReturnValue ピンから Promote to Variable(変数へ昇格) して、一旦 "専用の"の変数を作成します。

f:id:hiyokosabrey:20190208225734p:plain

f:id:hiyokosabrey:20190208230257p:plain

Variablesのリストに追加されているので、Detailsから配列に変更します。

f:id:hiyokosabrey:20190208230311p:plain

この操作は、一旦グラフから取り除いてからやると、エラーチェックが走らないのでオススメ。つながった状態でやると警告されます。

 

で、数字パネルをWrapBoxに追加した後は、数字パネルを出現させます。

f:id:hiyokosabrey:20190209034203p:plain

出現開始をする前に、アニメーション終了の通知が欲しいので最後の数字パネルにバインドを施しておきます。そして再び ForLoopを使って一斉に数字パネル全部に数字を渡しつつFADE_INのアニメーションを再生させる関数を呼び出しています。

その関数はこちら。

と、その前にカスタムイベントを準備。

f:id:hiyokosabrey:20190209034855p:plain

数字パネルのバインドで送り返してもらう値がInteger型で2つあります。それを受けるのであらかじめこちらでも2つのInputピンを装備させます。このイベントは後から作っても大丈夫。でも少しだけ手数が増えます。その理由はこれ↓

f:id:hiyokosabrey:20190209170308p:plain

関数の中にカスタムイベントを置くことはできないので、替わりに CreateEventノードをつなぎます。

f:id:hiyokosabrey:20190209170731p:plain

バインドノード経由のイベントをつなぐと、Select Function というプルダウンリストが出てきます。そこでイベントディスパッチャーの値を渡せるイベントを指定するのですが、Inputピンの型と数が一致していないと、プルダウンに出てきてくれないのです。

 

そのカスタムイベントの続きはこんな感じになります。

f:id:hiyokosabrey:20190209172342p:plain

クリックした数字パネルから応答が返ってきた値を比較して、同じなら成功なので、クリックした数字パネルの演出イベントを呼び出します。まだ数字パネルが残っているかどうかチェックして、残っていれば順番をチェックするカウンター用の変数を一つ進めます。

 なんとか 25までクリックできたら、終了処理に移ります。続き。

f:id:hiyokosabrey:20190209174108p:plain

Complete! のテキストを表示して、残ったパネルを消すイベントを呼びます。

 

そろそろ大詰め。ゲーム開始用のイベント。

編集モードをDesignerに変えて、Click To Start 用のButtonパーツを選択。

Detailsタブの一番下に、グラフにイベントを生成するボタンがあるので、On Clicked をクリック。

f:id:hiyokosabrey:20190209180903p:plain

f:id:hiyokosabrey:20190209181039p:plain

ここにゲーム開始の処理をつないでいきます。

f:id:hiyokosabrey:20190209175430p:plain

最後にフラグを True にしていますが、これはタイマー表示に使います。

 

タイマーは  ゼロから始まる~ のでEvent Tick で Float型の変数に加算していきます。

f:id:hiyokosabrey:20190209182303p:plain

ここで便利なノードが、 FormatTextノード。

「単位」をくっつけたり、文章の途中に任意のテキストを挿入するといった使い方ができます。

  詳細は公式サイトにあります→  ユーザーに表示するテキストの書式設定

 こちらのブログエントリーもおすすめです→ UE4ワイルドカードを使った書式設定で文字列を作成する

 

イメージしやすそうな例で説明を書いてみます。

 

取り出した直後はこんな形。

f:id:hiyokosabrey:20190209183359p:plain

ここにピンを増やすのですが、増やし方が変わっています。

例えば、こんな文章があったとします。

 

 おおトンヌラよ、しんでしまうとは ふがいない。

 

この名前のところを、半角の中括弧(波括弧)でピン名を挟んだ形、{ ピン名 }に置き換えます。

 

 おお{CharacterName}よ、しんでしまうとは ふがいない。

 

これを FormatText に入力してみると、こうなります。

f:id:hiyokosabrey:20190209184036p:plain

新たに入力ピンが追加されます。

{ピン名} はいくつでも配置できます。

f:id:hiyokosabrey:20190209184527p:plain

今回は、簡単に Float型の値に、 sec をくっつけています。

{Time}sec

 

これで一通りの用意ができました。

レベルブループリントからViewportに追加して、マウス制御用のノードをつないで、

f:id:hiyokosabrey:20190209185732p:plain

再生してみます。

www.youtube.com

 マウスカーソルがキャプチャできなかったのでちょっとわかりにくいかもですが、一通り遊べてます。

も少し整えないといけないところがあるのですが、そのあたりは次回に回そうと思います。

何度かチャレンジしてみて、なかなか12秒を切れなかった。パネルの大きさとかも影響するかもしれない。数字の色とか、フォントをいじるとまた違った難易度になると思います。一度つくってみるといろいろアレンジしたくなるので楽しいですね。

 

ではでは

ステキなパネルクリックライフを!