UI ボタンでカメラを切り替える《後編》
前回の続きです。
前編ではカメラを切り替えるUIをWidgetで作って、レベルにオブジェクトと切り替えるためのカメラを設置しました。
後編は実際のカメラ制御の部分を作ります。
Blueprint Interface
まず、Widgetからメインカメラ用のブループリントにアクセスするためのインターフェイスを用意します。
コンテンツブラウザから右クリックで、Blueprints > Blueprint Interface を選択。
このブループリントインターフェイスの中身は 関数名 とその 入出力ピン の設定のみで構成されています。
今回の関数名 SwitchCamera を作成して、Inputs に Integer型のピンを1つだけ追加したらコンパイルして保存します。
メインカメラ用Actor
次に、メインカメラ用のブループリントを用意します。
今度は Blueprints > Blueprint Class を選択。
ダイアログから、Actor を選択します。
さっそく編集していきます。その前にさっき作ったブループリントインターフェイスをセットします。
できたブループリントを開いて、ツールバーの Class Settings をクリック。
Details(詳細)パネルから Interface の項目を探してセットします。
ブループリントインターフェイスがセットできたら、次はメインのカメラを追加します。
まずは左上の Componentタブから、+Add Componentボタンを押して Camera を選択します。
次は変数を用意します。
一番上の CameraActor型の配列変数は、 レベルに設置したカメラにアクセスするためのものです。これだけ目玉のアイコンが付いているのは、以下のチェックボックスにチェックを付けているからです。
この2つにチェックを付けると、このブループリントを Spawnする際に値を受け取れるようになります。(Expose on Spawn だけだと 警告が出る)
変数が用意できたら次は関数を2つほど用意します。
配列に格納されたカメラの情報を取り出すのと、メインカメラにパラメータをセットする関数です。
まずは情報を取り出す方。getCameraPosition と命名。
中央下のノードは、ちょっと見つけにくいです。
get ノードからドラッグして、 get comp あたりで検索をかけて下の方。
カメラのアイコン付きを選択。
あとは、get Field Of View ノードと、 getActorTransform ノードです。
その二つを、Returnノードの Outputsピンから出します。
また、このGetCameraPosition関数は Pure型にした状態で作っていきます。
次は情報をセットする方。setCameraPosition と命名。
Transform と FOVを setするだけです。セットする先は別になります。
変数と関数が用意できたので、次はイベント。
Event BeginPlay
まずカメラを乗っ取ります。
※GetCameraPosition関数は Pure型で利用しています。
Set View Target with Blend ノードに Self ノードをつないでいます。このSet View Target with Blendノードは、先に get Player Controller を取り出してからだとすぐに見つかります。
あとは、用意した関数をつないで、開始時のカメラ位置をセット。
Event Switch Camera
ブループリントインターフェイスに仕込んでおいた名前だけの関数みたいなやつを、イベントとして利用します。
グラフで右クリックして SwitchCamera を探すと見つかります。
これはイベントとしておくことで呼び出してもらうかたちとなります。
右上にブループリントインターフェイスのアイコンが付いたノードが出てきます。
ここにカメラ切り替えの処理をつないでいきます。
まずは前半部分。あらかじめ用意した変数と関数を並べるだけ。
※GetCameraPosition関数は Pure型で利用しています。
今のカメラ位置(Old)から、新しいカメラ位置(New)へ移動させるために、それぞれの値を一旦変数に取り置きします。
常に最新のカメラ番号を保持させる Current Index 変数ですが、更新するタイミングがとても重要。つなぐ順番によって結果が変わるからです。
残りの後半部分。
いよいよタイムラインノード登場です。
タイムラインノードのトラックは Floatタイプ が一つだけ。
これでメインカメラActorの完成です。
ボタンWidgetを並べるWidgetの再編集
メインカメラのActorも用意できたので、Widgetの方からアクセスする仕組みを作ります。ボタンWidgetを並べるためのWidgetを編集します。
カメラにアクセスするために、Actor型の変数を新しく追加します。
Instance Editable と Expose on Spawn にチェックを付けておきます。
この段階ではまだどんな Blueprint Actor が入るか判りません。ただのActor型です。
あたりまえですが、中身にアクセスしたり関数を呼び出したりはできません。
さてこれを、放っておいたバインドからのカスタムイベントにつなぎます。
この空っぽのActor型のオブジェクトに対して、SwitchCamera の関数を取り出してつなぎます。右上に手紙のアイコンが付いたノードが取り出せます。
これは、プロジェクト内にブループリントインターフェイスが存在すると、見つけることができるというちょっと特殊な関係性によるもの。
その対象がなんであるかも構わず、中に関数を持ってるかどうかも関係なくつなぐことができます。
こんな状態でコンパイルが通ってしまうのです。
試しに適当なオブジェクトにつないでみてもコンパイルは正常です。
再生してもエラーは出ません。
ブループリントインターフェイスにはこんな便利な仕組みが備わっているのです。
Widgetの再編集はこれだけです。
では最後の仕上げとまいりましょう。
Level Blueprint
レベルブループリントを編集します。
まず Spawn Actor From Classノードを取り出してEvent BeginPlay につなぎます。
Class のところに、用意しておいた BP_MainCamera をセットします。
すると Expose on Spawn にチェックをつけておいた配列が入力ピンとなって現れます。
ここにカメラを配列にしてつなぎます。
最近知ったのですが公式に便利な操作方法が載ってました。
まず、レベルに置いたカメラたちを全部、複数選択状態にします。
そしてレベルブループリントのグラフ上で右クリックして、
Create References to X selected Actors を探します。
結構紛れて探しにくいのですが、 cr ref で検索するとすぐ出てきます。
これを選択すると・・・
結構便利かも。
このうちの一つから、Make Array ノードを取り出してつなぎます。
これで配列化できました。
これをさっきのSpawn ノードにつなぎます。
Spawn Transform ピンに何もつながれていないとコンパイルした時にエラーがでます。
これはTransformについて適当な初期値を渡してやれば消えてくれます。
オレンジ色のピンからドラッグして、Make Transform を選択します。
こうなります。
これで、再生したときにメインカメラのブループリントがワールドに誕生します。
あとはWidgetをViewportに描けば完成です。
Widget を表示するのは、おなじみ Create Widget ノードと Add to Viewport ノードのコンボです。
Create Widgetノードも Class を変えると入力ピンが増えます。
ここと、先ほどの Spawn Actor from Class の Return Value とをつなぎます。
ようやく完成です。
再生してみます。
静止画だとタイムラインの動作が伝わらないので動画にしました。
使っているタイムラインは1つです。
ブループリントを触らなくても、カメラのアングルやFOVはワールドに置いてあるカメラを直接触ればすぐに反映してくれます。気に入ったアングルはレベルを保存するだけです。
いかがでしょうか?
キャラクリエイションとかで使えそうな気がします。
例えばキャラの身長に合わせてカメラの距離を調整したりとかも、今回の方法ならタイムラインノードをいじらずに臨機応変に補正ができます。
結構長くなりましたが、今回はここまで
ではでは
ステキなカメラ切り替えライフを!
UI ボタンでカメラを切り替える《前編》
突然ですが、ブループリントのタイムラインノードってものすごく便利なのです。
UMGには専用のタイムラインが装備されていますが、UMG以外でUIのインタラクションを表現する際に利用します。
ただトラックに直接的な値のKeyを打ってしまうと、とたんに汎用性が無くなってしまいます。
先日のぷちコン第11回でも使った方法なんですが、ちょっと扱い方を工夫するだけで汎用性が高くなってさらに調整がラクになる方法があるので記事にしておくことにします。
賢明な読者諸兄はすぐに気づかれるかと思いますが、種明かしをするとこれです。
タイムラインノードから出てくる値は、0.0 ~ 1.0 のみ。
この1個のタイムラインを値を煮るなり焼くなりして使い回すのです。
掛け算したり、
↑この場合、0.0 ~ 5000.0 の値でアニメーションします。
また 0.5から引き算して、2倍すると、 -1.0 ~ 1.0 の値のアニメーションが可能。
しかも、カーブを調整すれば好みのイージングも作れます。
変に計算が増えると処理への負荷が無視できなくなりますが、ほどほどに、汎用的に使えるカーブを効率よく使えば、調整にかかる時間が減るのでおススメです。
さらにこれを便利に活用するためのノードが、Lerp 系のノード
扱う型専用にいくつか用意されているようです。
入力ピンの 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 を左のリストから探してキャンバスに 配置します
Anchor は ストレッチ(親要素に合わせて最大まで拡大)でドーンとスクリーンサイズに。Anchor を変えただけでは変化しないのでパラメータを変えます。
Button の Slot(Canvas Panel Slot) は ↓ こんな感じ。
中にTextBlockを子供として持たせます。
TextBlockは ↓ こんな感じ
階層構造は↓下のようになってます。
ここで、クリックイベントを作成します。
配置した Button のDetails(詳細)パネルの下の方に緑色のボタンが並んでいるので、
On Clicked のボタンをクリックします。
強制的に編集モードがGraphモードに切り替わります。
イベントノードが置かれていますが、一旦置いておきます。
Integer型の変数をひとつ追加します。
自身が何番目のボタン番号かを受け取っておくためのものです。
次にカスタムイベントを用意します。
Inputピンに、Integer型とText型を追加して、作っておいた 変数 と TextBlock にそれぞれつなぎます。
次はイベントディスパッチャーを用意します。
Inputsのところで+ ボタンを押してInteger型のピンを追加します。
このイベントディスパッチャーを、On Clicked イベントにつなぎます。
イベントディスパッチャーをグラフにドロップすると小さなコンテキストメニューがポップするので、 Call を選択します。
クリックされたら、自分が持たされているボタン番号を返す仕組みです。
コンパイルして保存します。これでボタンWidgetは完成です。
ボタンWidgetを配置するWidget
次にボタンを並べるための親になるWidgetブループリントを用意します。
キャンバスに HorizontalPanel をひとつ配置します。
Slotはこんな感じ。
このHorozontalPanelに、先に作ってあったボタンのWidgetを追加します。
既に作成済みのWidgetブループリントはアセットになっているので、
UserCreated カテゴリで探すと見つかるはずです。
それを Hierarchey パネルの HorizontalBox 以下にドロップします。
とりあえずカメラを5台置く予定なのでその数ぶん追加します。
追加したらそのまま、まとめて選択状態にします。
レイアウトの設定を変更します。
Size が 初期状態でAuto になってるのを Fill に切り替えます。
HorizontalPanelにぴっちり並んでくれるはず。
キャンバスはこのくらいで。
グラフの方を編集します。
まずは並べたボタンたちを一旦配列にします。配列にした方がForEachLoopが使えるのでこ後でちょっとラクができます。
ざっくりですが手順をGIFにしてみました。
次にボタンのラベルをテキスト型の配列で用意します。
一度コンパイルすると、DefaultValue(初期値)がセットできるようになります。
ここで ForEachLoopの出番です。
右端のノードは、イベントディスパッチャーが存在することが前提で、そのイベントディスパッチャーにBind(バインド:紐づけ)することが可能になります。そうすることで、ボタンのWidgetからイベントディスパッチャー経由で通知を受け取ることができます。要するにボタンが押されたら、カスタムイベントが実行されます。
カスタムイベントにはとりあえず今は何もつなげないで、コンパイルしてみます。
すると、キャンバスが変化します。
Event Pre Cnstruct につないだ処理は、Play していなくてもコンパイルした時点で、キャンバスに配置したものに影響を与えることができます。
Widgetは一旦ここまでにします。
カメラの設置
次はカメラとステージを 用意します。
準備としてレベルに、カッコイ風景とカッコイイオブジェクトを設置します。
レベルに直接カメラを5台配置。アングルを決めます。Field Of View(視野角)も調整します。
前編はここまで。
後編は、メインカメラの作成と制御を作っていきます。タイムラインは後編で登場します。
ではでは
ゆらゆらするマテリアル
なんとか第11回ぷちコンに応募することができました。今回はギリギリまでかかってしまってキツかった。今使ってるPCではパワー不足だということが思い知らされた感があって寂しくはあるけど、あきらめた表現がたくさんあったのもまた事実で、もう買い替えをためらっている場合ではないのだと強く思った次第です。なんてことを書いてますが、かなりの部分は自分の頭の悪さだったりして・・・すみませんマシンパワーのせいにしました。てへぺろ。
実際シェーダーコンパイルに時間がかかり過ぎたのと、半透明に落とす影の調整に時間がかかり過ぎました。
応募した動画を貼っておきます。
動画編集はいまだに不慣れなので、編集に時間を掛けられないと判断。実際にプレイしたキャプチャをそのままノーカットでアップしました。さすがに前後の黒い余白時間をカットするくらいはしてますが、ほんとそれだけです。
なので、画面遷移やUI表示は職業柄それなりに頑張って作ったつもりです。
まぁそんなこんなで、ブログの更新が止まっていたわけですが、久しぶりに書こうと思います。ネタはぷちコンからで、仕組み自体は過去記事でも紹介したものの応用になります。
ゴールした時の誉め言葉表示です。
この水の屈折のような表現。ディストーション(歪み)エフェクトとも呼ばれるようですがマテリアルで簡単に作ることができます。
まずは ゆらゆら させるためにはランダムな2D素材が必要です。Noise ノードを使うとテクスチャが不要にできるのですが、やっぱり滑らかさが欲しいので今回 Photoshopを使ってテクスチャを用意するところから説明していこうと思います。
あの有名なフィルタを攻略する
ランダムといっても大きなテクスチャはそのままテクスチャメモリの負担となるのでなるべく小さく、かつタイリングできるように作ります。
そこで登場するのがおなじみのフィルター「雲模様1」
ちなみに↑これは、 512x512 で作成したものを 50%に縮小した状態です。
このフィルターは、2のべき乗で作成すると上下左右がつながったシームレスな状態になります。
フィルター > その他 > スクロール を使うとつながりが確認できます。
2のべき乗というのは、2を何乗かした値で、2、4、8、16、32、64、128、256、512、1024・・・という数字です。縦横をこの数の解像度にすると見事シームレスなテクスチャの完成です。ちなみに他の解像度で雲模様を作ると、つながらなくなります。
これは 250x250で作成してスクロールさせた状態。よく見るとつながっていないのが判ります。下の図はニアレストネイバーで400%に拡大した状態。
これが「雲模様1」の特徴です。
ちなみに、この「雲模様1」は、フィルタを掛ける際に、描画色と背景色の2色を使って作られます。なので、今回のようにモノクロでしっかりと階調差を出したい場合は、直前に D キーを押して、白黒にしておくのをお勧めします。
あと、注意したいのが「解像度」です。雲模様フィルタは、密度の調整ができないので、解像度でコントロールすることになります。
ヒストグラムで比較するとさらに差が分かりやすくなります。
という訳で濃淡の散らばり具合を考慮して今回は 1024x1024で進めます。
素のままだとノイジーなので、ここから加工していきます。
水の揺らめきなので、もっと滑らかな感じが理想。
ボカしたり、明るさの中間値を掛けると速いのですが、この状態でかけると、せっかくシームレスにしたのが台無しになってしまいます。フィルタはドキュメントの上下左右がつながっているなんて気にしないからです。
そこで、面倒ですが一旦 手動でシームレスな状態にします。
まず 新規ドキュメントを 1024x1024で作成して「雲模様1」を使用します。
この状態で、全選択(Ctrl+A) からの コピー(Ctrl+C)までを実行。クリップボードに入れた状態で、カンバスサイズを変更します。
するとこうなります。↓
ここからクリップボードに入れたのをペーストしていくのですが、ちょっとだけ時短できるぷちテクニックを紹介しておきます。選択範囲を作ったペースト方法です。
まず左上に貼り付けたい場合、マウスを下図のように外に向かって適当に動かします。
すると、
このような選択範囲になるので、ここでペースト(Ctrl+V)します。
これを4隅で行います。
上下左右も同じ要領で適当に選択範囲を作って、
ペースト&ペースト。
多少ずれても中央揃え機能を使えばビシっと隙間なく並びます。
アナログな手操作を確実でブレのない結果にするのが大好きなので紹介しましたが、この時点でピクセルがずれていなければどんな方法でもOK。Photoshopは作業中の表示倍率がキリの悪いときはかなりの確率でピクセルスナップが甘くなるので、こういった倍率に関係なく確実な操作は重要です。
この9枚がビシっと並んでいる状態でようやくフィルタを掛けます。
せっかくタイリングするように並べたので、ランダム系のフィルタはNG。あくまでもピクセルに合わせて均等に掛かるタイプのフィルタを使います。
今回は、明るさの中間値 を掛けてから ぼかし(ガウス)を掛けました。
ここで解像度を落とします。
最終的に 256x256 のテクスチャにしたいので、256x3 = 768
768x768 に縮小します。もちろん縮小されるときにもピクセルにフィルタが掛かります。
ここで、カンバスサイズを使って 周りの 8枚をカット、中央の1枚だけにします。
シームレスになっているかどうか、「スクロール」を使って確認してみましょう。
つなぎ目が見えなければ完璧です。
これをリニアなグレースケールテクスチャとして、UE4に持っていきたいので、ドキュメントをグレースケールに変更します。イメージ > モード > グレースケール を選択。
おそらくポップアップが表示されるので、カラー情報は破棄します。
チャンネルが 「グレー」だけになったらOK。
あとは、これをTarga フォーマット(拡張子 .tga)で書き出せば UE4 にインポートできます。
PNG形式はチャンネルが一つだけ(SingleChannel)という仕様を持っていないため、PNGで保存した際にRGBA32ビットに戻されてしまいます。なのでグレースケールテクスチャの場合は、PNGは使っちゃダメです。チャンネルが一つということはそれだけテクスチャのメモリが1/4になるということで節約になります。
今回よりランダム感を出したいので、もう一枚用意します。
↑ Web用にPNG形式になってますが右クリックしてDLしてもらってOK
この2枚をUE4にインポートします。
いざUE4へ
インポート設定はこんな感じです。
今回 sRGB のチェックは外しているので、リニアグレースケールテクスチャとして扱うという意味になります。これはPhotoshopでのカラー設定によって書き出す際の補正があるか無いかで決めます。特に何も設定をいじっていなければsRGBにチェックが付いていると思いますが、今回は特に問題ありません。
ちょうど一年前の記事ですが一応過去記事を貼っておきます。
これを使ってマテリアルを作ります。
Create Material して中にテクスチャをドロップします。
あ、揺らすためのテクスチャを忘れていました。せっかくなんで。
これをつなぐとこうなります。
速度は左のPannerノード で調整しつつ、揺れ幅というか揺れの度合いは、TexCoordノードで調整します。
参考までに今回の値。
さらに適応する量は、真ん中のScalarParameterValueで調整します。このパラメータノードは、Widgetブループリントから値を受け取って反映する役割のノードです。
雲模様のコントラストや濃淡によりますが、今回の値はこんな感じ。
まず、Amount: 0.15
かなり揺らめいてます。
次は Amount: 0.1 だいぶ落ち着いてきました。
Amount: 0.025
もちろん 0 にすると静止します。
ちなみに 0.5 はまったく読めません。
これだけで一つミニゲームが作れそうです。
なんて書いてあるでしょうか?さぁ早押しでお答えください! みたいな。
ただあまり揺らすと端の切れてる部分が目につくようになるので注意が必要です。
真ん中上の、Subtract(引き算)ノードでは、グレースケールテクスチャからやってきた値を調整しています。
ここでいう調整というのは、0~1 という範囲を、幅を変えずに -0.5~+0.5 にすることです。テクスチャの黒は 0.0、白は 1.0なので、このまま足し算して使うと、揺れはしますがプラスの方向にしか揺れないので、結果的にテクスチャ全体がプラス側に寄ってしまいます。それをプラスとマイナスの距離が均等になるようにしているのです。
マテリアルはこれで完成です。
ちなみに、↓こんなテクスチャだと。
こんな感じにできます。
Widgetでフェード
まずキャンバスに、Imageを配置します。
配置したら、Detailタブから、Appearance > Brush > Image の部分に用意したマテリアルをセットします。
さらにもう一つ、Imageをキャンバスに追加します。
これは描画しないのでVisibilityを Collapseにしておきます。
ここでアニメーションを用意します。
アニメーションさせるのは2つ。
一つは、Collapseにした方の Pivot。もう一つは、表示する方の Render Opacity 。
つぎにブループリントを用意していきます。
初めから置かれているイベントノードをそのまま利用することにします。
Event Pre Constructから。
Image にセットしているマテリアル(Static)をいじるには、マテリアルを、Material Instance Dynamic型 にする必要があって、Get Dynamic Material ノードを使うと型変換しつつ、置き換えてくれます。この変換処理を頻繁に行いたくなくて、一度きりで十分なので、ReturnValueから Promote to Variable(変数に昇格)させています。
Event Construct。
アニメーションの再生が終わったら、後片付けしてViewportから姿を消します。後片付けといっても変数を空にしてマテリアルへの参照関係を解消するだけです。
最後に、Event Tick。
Widgetは完成です。
テスト用の新規レベルを作ってテストしてみましょう。
レベルブループリントに Create Widget ノード と Add to Viewport ノードをつなぎます。繰り返し確認したいので、Inputノードで何度でもWidgetを呼び出せるようにします。とりあえずスペースキー。
再生してみます。
いい感じです。青い背景を置いたので、マテリアルの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つのノードで扱う値は、以下のようになっています。
Get Viewpor Size は表示されている解像度です。(基本的に可変します)
Get Desired Size にはキャンバスに置いたときの値で、スケールが掛かっていません。
ここまではGET。最後にSET。
このようになっているので、@ghosticgames さんの手順をみてみると、基本的に スケールの掛かった ViewportSize ベースで計算して、表示位置が確定した後に ViewportScale で割り算して、1920x1080空間用に合うようにしています。
Get Desired Sizeで得た追随用パーツのサイズに ViewportScaleを掛けているのは、スケールを揃えないとこの後の計算がおかしくなるからです。
ではこの辺で Clampさんのお仕事紹介と行きましょう。
Clampは3つの入力ピンがあります。
Value から入った値が、Min と Max の範囲を越えても、Min(下限) と Max(上限) の範囲から出ないことを保証してくれるという代物。
下図はイメージ。
例えば、Max に 1.0 が設定されている時に、 Value が 2.5 だとすると、強制的に 1.0 になります。
この仕組みを使って、表示座標に制限を付けるのです。
アクターの表示位置を3D→2Dに変換する ConvertWorldLocationToScreenLocationノードは、スクリーン座標の限界を超えた値も返してくるので、Clampノードにスクリーン座標の最小値、最大値を設定してやります。
このとき、追随するWidgetがはみ出さないないようもしたいので、そのぶん内側に制限を付けることになります。
ViewportSize から 追随するWidgetの表示サイズの半分のサイズを内側に入れればよいということになります。改めてノードを見てみるとこうなってました。
Local Desired Screen Location はアクターのスクリーン座標です。Viewportの左端は 0 から始まるので、 Min は 追随するWidgetの半分のサイズになります。Max はViewportサイズから 追随するWidgetの半分を引き算すれば求まります。
これで、画面内から絶対はみ出さない仕組みが実現できます。
ということで、ここからは、オマケの仕組みを組み込んでいきます。
グラフを開いて、空いているところに、表示する値を受け取るためのカスタムイベントを準備します。
カスタムイベントは Float型の ピンを追加します。
数値に単位の文字「 m 」をくっつけたいので、FormatTextノードを使います。
このノードは、定型のテキストに変数を差し込むことが出る便利なノードです。
{ }でピン名を囲って使います。上の例では、{0}m と入力しています。⑤
過去記事にもう少し詳しく書いています。
UE4の単位は、Project Settings > Editor > Appearance で設定されています。
デフォルトでは cm(センチメートル)に設定されています。
今回 単位を m(メートル)にしたいので、100で割ります。⑥
割り算の結果と FormatTextノードを直接つなぐことが可能なのですが、小数点の桁数を変更したいので、 ToText (Float)ノード を利用します。⑦
この ToTextノードは詳細設定ができます。
Minimum Fractional Digits を 1 にすると、キリのいい値のときでも、0 を表示するようになります。
これでWidgetの編集は完了です。
コンパイルして閉じます。
次は、このWidgetに距離を調べて渡す部分。
レベルブループリントを編集します。
すでにつないである部分2つ目の Create Widget のReturn Value ピンで右クリックします。
Remote To Variable (変数へ昇格)を選択して、変数化します。
これに名前を付けて、間に挟み込みます。
この操作で、追随するWidgetに対してアクセスが可能になります。
これをEventTickで使用します。
対象の3Dオブジェクトと、プレイヤーカメラの距離を表示してみます。
双方のポジションを取得して引き算すると差分が得られます。それを VectorLength ノードが距離として返してくれるので、これを利用します。
最初3次元上の2点の距離を調べる公式を使ってノードを組んでいたのですが、
ブループリントで数式を組むとなんだか不思議な感じがするのは気のせい?
検証している途中でステキな記事を見つけたので、シンプルな VectorLength を使った形に変えました。
これで完成です。
再生して確認してみると、
ここまで来たらあとは見た目をゴニョゴニョするだけですね。
いかがだったでしょうか?
実際に組み込もうとすると、もっと機能性や汎用性を持たせた方がいいと思いますが、ゲームメカニクス次第なところもあってこれ以上は踏み込むのは難しいかな。
とはいえ結構個人的に面白いネタだと思うので、もう少し遊んでみようと考えています。
分かりにくいとことかあれば↓コメントかツイッターで質問OKです。
こんこんと泉のごとく沸き続ける鼻水と目のかゆみと闘いながら変なテンションで書いています。
いちいち眼鏡外さなくてもさりげなく点眼する方法って開発されないかな。
ではでは
ステキなマーカーライフを!
3Dオブジェクトの上にWidgetをマーカーのように表示する。画面外にいっても大丈夫。操作手順もできるだけ丁寧に書いてみたけどどうかな?
前回の更新からちょっと間が空きましたが、ぷちコン作品を作ってました。
で、先日とあるツイートに目がとまったのです。
Howdy, gamedevs! Ever wondered, how to prevent widgets in #UE4 from going off screen like this? I think this is a common issue and here's how to do it! #indiegame #indiedev #UnrealEngine #roguelike #Tutorial pic.twitter.com/OR7hEyisgq
— Ghostic Games (@ghosticgames) March 3, 2019
これは、Worldに存在する Actor の上に Widget を表示するという内容で、さらに対象の Actor が画面外に出ても、画面の端に張り付くようにするという 素晴らしいものです。
3Dオブジェクトの上にWidgetを表示するという方法は、すでにブログ等で公開されているので、目新しさは無いですが、画面の外に出ないようにする工夫に心惹かれました。
ツイ主の @ghosticgames さんにブログで説明してもよいかコメントで確認したら、"Sure! "(もちろん!)という返事を頂けたので、さっそく当ブログで説明させていただくことにしたわけです。質問箱からもブログのネタにどうかという提案(いい感じに解釈)もあってこれはもうやってやるしかないなと。
まずは、さっそくツイート画像を見ながら全く同じように試してみました。
その結果がこちら。
@ghosticgames さんのツイートされてた BPをそのまま組んでみて、距離を出せるようにしてみた。#UE4 #UE4Study #ue4UMG pic.twitter.com/eiKXqYxbev
— みつまめ杏仁 (@MMAn_nin) March 4, 2019
(このツイート、「メディア」にはログとして残ってるけど「ツイート」には出てこなくなった・・・)
基本的な原理はとてもシンプルです。さっそく他の方法はないかとアレコレ実験してみたんだけど、扱い方次第になると思うので、今回は手を加えずに教材として説明してみます。
ツイートされてる画像とレイアウトや変数名などが若干違うものがありますが、基本のロジックは同じ構造です。基本的な動作を作った後でアレンジとして対象までの距離を表示するとこまでやろうと思います。
今回はUMGやブループリント編集に慣れていない方でも作れるように操作方法をなるべく細かく書くようにしてみました。(作業の能率がいいので英語環境をオススメします)
用意するWidgetは2つ。
まずは1つ目のWidgetから
キャンバスだけのWidget
コンテンツブラウザから、 右クリック > User Interface > Widget Blueprint
で作成できます。
できたらダブルクリックしてエディタを開きます。
エディタウィンドウ左にある、Hierarchy タブの中を確認すると、あらかじめ Canvas Panel_0 というのが置かれているので、クリックして選択。
続いて右上の Is Variable というチェックボックスにチェックを付けます。
付けることで、ブループリントからこの CanvasPanel_0 に対して直接いじることができるようになります。キャンバスパネル は UIパーツを描画するため使われます。
念のためキャンバスの描画サイズを確認。
これはこのWidgetを、画面いっぱいまで使って描くよ、という意味合いです。
このWidgetブループリントはこれで完成です。
コンパイルして保存したら閉じてもOK.
次は2つ目のWidget
Actorをフォロー(追随)するWidget
今度はキャンバスのサイズを指定します。
Fill Screen と書かれている部分は、プルダウンメニューになっているので、Custom を選択します。
幅(Width)と高さ(Height)を指定できるようになるので表示したい適当なサイズ(単位はピクセル)を入力します。今回は100x100で作りました。
次にキャンバスに、2つのパーツ Image と TextBlock を配置します。まずは Hierarchyパネル で ドラッグ&ドロップします。
ドロップしたら、エディタウィンドウ右のDetails パネルで設定をいじっていきます。
Image の方から。
Anchor(アンカー)はそのままでOK。
キャンバスの中めいっぱいになるように、Sizeをキャンバスの大きさと同じ値を入力します。
あとは Detailsタブの Appearance > Tint で好きなカラーをセットしたら下敷きは完成。
次にTextBlock。
こちらもAnchorを設定します。
中央揃えにしたいので、『Top-Center(勝手に命名)』 を選択。
パラメータは以下。
テキストのカラーと文字サイズを決めて、レイアウトをセンタリングにします。
あと、これもブループリントから内容を書き換えるので、Is Variable にチェックを付けておきます。
キャンバスがこんな感じになればOK。
いよいよブループリントを編集します。
編集モードを切り替えます。
切り替わったら、グラフの何もない所で、右クリックします。
Add Custom Event を探します。Search のところで検索ワードを入力するか、一番上にAdd Event というカテゴリを開くと見つかります。(←英語環境)
見つけて選択するとノードが現れるので、
InitFancyFollowingWidget と名付けておきます。
ここにパラメータを受け取るための 入力ピン を追加します。
このノードを選択したまま(オレンジの枠線をつけた状態)Detailsタブを見てみるとInputs という項目があるので、右にある + ボタンを 静かに2回クリック。
適当な型の設定項目が2つ並ぶので、上からプルダウンを開けて、
Actor を探します。
2つ目は
Canvas Panel Slotを探して選択します。
下のようになればOK。
PINの目的(役割)を後から思い出せるように、それぞれに名前を付けておきます。
これでグラフに置いたノードが変化します。
次は変数を用意します。この青いピンからドラッグして作成します。
Promote to variable(変数へ昇格)を選ぶと、ピンと同じ型の変数が、SETノードの形で現れます。
名前を付け直したら、2つ目のピンも同じようにして変数化します。
これで、ターゲットとなる Actor と配置用の キャンバスパネルスロット にアクセスするための準備ができました。まだこの時点では中身はなくて空っぽな状態です。型が決まった器があるだけです。
変数化できたので、エディタウィンドウ左にある、Variables のリストに追加されているのが確認できます。そこから、グラフにノードとして取り出します。
Ctrlキーを押しながらドロップすると、いきなり GET のカタチで取り出せます。
ちなみに Altキーだと、SETのカタチで取り出せます。
このノードの中身が入っているか確認してから処理するので、確認用のノード is Valid をつなぎます。
なんらかの不具合や処理順などで受け取りを失敗することがあります。その時は中身が無効になることがあるので、このノードでチェックするのが安全です。今回は 両方が有効の場合のみ 処理したいのでAND(Boorean)を使います。これは論理式というやつで『 A かつ B 』という意味になります。両方のIsValid ノードの結果が true になってようやく true になります。
これらを、グラフに最初から置かれている赤いイベントノード、Event Tick ノードにつなぎます。
右端は、表示位置をセットするノードです。変数CanvasSlotをもう一つGETで取り出すと、そこから安全に取り出せます。
仕上げに、ポジションを計算する関数を用意します。
今回の要の部分です。
座標計算用の関数
MyBlueprintタブの Functions のところにある +ボタンをクリックして新しい関数を準備していきます。
名前を ProjectWorldToScreenClamed としておきます。
グラフが切り替わっているので、ノードをつないでいきます。ちょっと長めです。
まず、①Get Player Controller 、そのReturn Value からは、②Get Viewport Size
右にある2つの変数は ローカル変数です。この関数内だけという限定された範囲で使うためのものです。関数の外では利用できない変数です。別の見方をするとこの関数以外での利用価値が無い、とも言えます。今回一時的な計算のためだけに存在するのでローカル変数を使用します。
作り方は、Get Viewport Size ノードの SizeX と SizeY のピンからドラッグ&ドロップするとポップアップメニューが出るので Promote to Local variable を選択すると簡単です。
エディタ左の MyBlueprintタブに、関数を編集している時にだけ現れる Local Variables であらかじめ用意しておくこともできます。
ドラッグして作る方が、VariableType(変数の型)が確実に設定されるのでオススメ。
まず Viewport の大きさ(画面表示サイズ)を変数に入れておきます。
今度はこのWidgetのキャンバスに置いたパーツのサイズを取得して、これもローカル変数に取り置きします。
まず①Get a reference to self ノードから始めます。
②Get Desired Size は表示しようとしているサイズを返します。Self(自身)に対してつないでいるので、キャンバスに配置したすべてのパーツを含めた最終的な表示サイズのことを指します。
③は vector2d と Float を掛け算するノードです。ドラッグ&ドロップして *(アスタリスク)で検索すると見つかります。
④Get Viewport Scale は、ディスプレイ解像度を 1 として、UE4実行時に実際に表示されているウィンドウの表示倍率を返してくれます。
ディスプレイの解像度設定は公式ドキュメントにあるように設定ファイル "GameUserSettings.ini" に書かれています。
⑥は 複数の型で構成されているVector系のデータを分解してくれるノードです。Vector2D 型 は Float型のデータを2つ束ねています。主に XY座標を扱う場合などで使います。
⑦と⑧は これも ローカル変数に格納します。
まだまだ続きます。
これはワールドにあるアクターの座標をScreen座標に変換します。
用意しておいたカスタムイベント InitFancyFollowWidgetで受け取っている変数オブジェクトを変数リストからドラッグ&ドロップして始めます。
そこから② Get Actor Location でアクターのワールド座標を取得 → ちょっとだけ位置をずらします。
ConvertWorldLocationToScreenLocation というノードで、3次元のワールド座標を画面で見ている2次元のスクリーン座標に変換します。このノードは、先にGet Player Controller ノードを取り出しておくとスムーズに取り出せます。④→⑤
ここにアクターのポジションを渡してやります。
これをまたローカル変数に取り置きします。⑧、⑨
右端のは Returnノードです。 関数には基本このリターンノードを置きます。関数というからには何かしら計算や処理した結果があるので、この Return ノードから、外に出してやるのです。ノード検索キーワードに ピリオド 「 . 」 を入力するとすぐ見つかります。
このリターンノードには アウトプット用のピンを追加できます。リターンノードを選択して、Detailsタブから追加します。
このリターンノードで返す値がこちら。
取り置きしてきた座標やサイズの値をここで一気に計算します。
上段が X座標、下段がY座標用です。それぞれ Clampノードではみだしをカットしています。今回の一番重要な処理だと思います。
Integer型 と Float型 の引き算はそのままではできないので、Integer型をFloat型にキャスト(型変換)してやります。
ノード検索で「 to 」と入力すると ToFloat(Integer) が選択できます。
こんなノードが出てきます。
全体図はこんな感じ。
@ghosticgamesさんのと同じ内容ですが、説明用にコンパクトにしました。
これで関数は完成ですが、最後の仕上げとして、この関数をPure型にします。
Pureにチェックを付けると・・・
グラフにノードとして取り出した際に、実行ピン(白色)がない状態になります。
これを途中だった EventTick処理につないだら完成です。
コンパイルして保存したらと閉じてもOK。
表示を確認してみる
ワールドに適当なオブジェクトを配置します。
実験では、Transformを持ってさえいれば動作すると思います。
配置できたら、手っ取り早いのでレベルブループリントを使って確認します。
レベルブループリントの編集方法はこちらから。
グラフ編集エディタが開きます。
①Create Widget からつないでいきます。
アクターに追随するWidgetは、Viewort に追加せずに、先にAdd to Viewport したキャンバスだけのWidget内に持っている CanvasPanel の子供にします。
さらに続き、
スムーズにつなげるコツは、白い線は気にせずに、Return Value からドラッグして検索することです。つながるのが約束されているノードが取り出せるので安心です。
⑧Set Auto Sizeノードは Inb Auto Size にチェックを付けておきます。
⑩はワールドに置いたオブジェクトをドラッグします。
この方法は可能なブループリントが限られます。
これですべての準備は整いました。
再生してみましょう。適当にカメラを動かしてみてください。
対象のオブジェクトが画面から消えても残り続けます。
これが Clampを使った移動制限です。
一応動画のURLを貼っておきます。
→ @ghosticgames さん版
細かくオペレーションを書いていたら思ったより長くなってしまいましたが、今回はこの辺まででいったん筆を置こうと思います。
次回、計算の仕組みを軽く解説して、オマケの「距離」を表示する部分を書きます。
@ghosticgames さん ステキな教材をありがとう。
ではでは
ステキなターゲット表示ライフを!
UMGパーティクル(なんちゃって)
Widgetでパーティクルっぽいやつを作ったのでTwitterに動画をあげたら、いいねしてもらえたので記事にしてみます。さくっとParticleをWidgetに乗せる方法が見つけられなかったのでUMGで作ってみた次第です。
変数の型に Box2Dというのがありまして、
これを配列にして管理したらいいんじゃね?ってなったのが作り始めたきっかけ。
BoxなんでRectangle(長方形)の4頂点のうちの対角の2点を扱うための型です。
2D座標ということで xとy を扱うVector2D が2つ束ねられているかたちです。
今回これをFloat型が4つあるという認識で扱うことにしました。
ちなみに 他に (x, y, z)の Vector型で2点をまとめた Box型や、BoxSphereBounds型というのもあるようです。ピンの色的にStructure(構造体)の類ですよね。
パーティクル用に格納する値は3つ。最終回転角と目的地の座標です。
ここに粒ごとのゴール位置と何回転するかの値を入れていきます。
Construct Object From Classノードで Widgetの Image を量産して配列に格納。ついでにパーティクルのパラメータを設定。右端のマクロの中身はこんな感じ。
発生源から ±500(50.0刻み)の範囲がゴール位置。±3 ~ ±7 回転。
次にキャンバスに追加。
OffsetPos と、 Color はこのパーティクルWidgetを呼び出すやつがセットするので、受け取るための設定をします。
パーティクルが発生してから、2秒後に消滅するようにタイマーをセット。Tickのためのフラグを立てて、フェードアニメーションを呼び出します。
フェードアニメーションは、キャンバスに対して Render Oapicty を 1.0 → 0.0 にすることでパーティクルを一斉に消します。
移動処理のTickは以下。
一粒ずつ処理します。ポジションと回転は、WidgetのRenderTransform を使います。それぞれの更新に必要な計算はマクロでやってます。
getNewTranslation
getNewAngle
これでパーティクルのWidgetは完成。
あとは呼び出すだけ。
クリックしてヒットしたときの処理に追加します。
パーティクルのカラーは数字の色同様に、あらかじめ配列で持っておきます。
できあがりです。
一応動画を確認するためのツイートを貼っておきます。
クリックゲームにエフェクト付けてみた。UMGでなんちゃってパーティクルを再現。需要あるかな pic.twitter.com/lVcuvE3SDa
— みつまめ杏仁 (@MMAn_nin) February 13, 2019
パラメータを工夫すると散り加減が変えられたりして楽しめます。
テクスチャを貼るとまた違った印象になると思います。
ではでは
今回はこの辺で
ステキなUMGパーティクルライフを!
クリックするだけの簡単なゲーム 《改造編》
さっそく前回作ったやつを改造していこうと思います。
改造ポイントは4つ。
- 繰り返し遊べるようにする
- タイマーのガクガク震えるのをなんとかする
- ちょっと難易度を上げてみる
- おまけ
まずは、クリアしたあとにボタンを表示したいので、キャンバスにButtonを追加します。作り方は開始時の Click To Start ボタンと同じ作りでいきます。
配置したら、Visibility を Collapsed にして非表示にしておきます。
このボタンを表示する処理をクリア時の処理に追加します。
ボタンが表示された次は、ボタンがクリックされた際の処理です。
エディタの Variables の欄に、Buttonが追加されているので選択して Details タブを更新します。
Events の項目に On Clicked があるのでクリックしてイベントノードを取り出します。
イベントノードを取り出したら、ひとまずボタンは用済みなので再び非表示に戻してやります。合わせて Complete! の文字も消します。
この後、いろいろと初期化と再セットをしていくのですが、一旦寄り道して、タイマーの改造を進めます。とはいえちょっとブループリントが賑やかになってきたので、改造というよりは新しくタイマー用のWidgetを作ることにします。
いつものようにキャンバスにパーツを配置していくのですが、Epicがストアで無料で提供してくれているプロジェクトを見ていて最近学習した方法があるのでそれでいきます。今頃ですが・・・
キャンバスのサイズはでデフォルトだと 1080pだったりしてPC環境やコンソールのゲーム機だとそのままで良かったりで、あまり気にしてなかったのですが、Widgetで部品パーツを作る際はなんかもったいないような気がしてました。
この右上の Fill Screen を 変更できることができます。
固定サイズなら、Custom、 中身次第にするなら Desired に切り替えるだけ。
タイマーはデジタル的に表示したいのでTextBlockをキャンバスパネルの子供にして表示桁ぶん並べます。
Desired にしていると キャンバスのサイズは自動的に合わせられます。
ピリオド以外は Is Variable のチェックを付けておきます。
ブループリントを編集します。
小数点の値を受け取って桁を分解してテキストを更新する関数を用意します。
桁の分解は、小数点の扱いがポイントになります。Fraction で整数部分を、Floor で小数以下を切り捨てることで、小数点を境界にして大きく2つに分けることができます。 あとはそれぞれで整数にして計算します。
図で解説してる過去記事を貼っておきます。
これで、数字の文字幅によるブルブルがなくなります。
この関数は外から呼ばれますが、初期値のセットも兼ねて、グラフにつないでおきます。
タイマーは完成。
メインのWidgetに戻って、配置します。
もとのTextBlockで簡易的に作ったタイマーをこのWidgetに差し替えます。
中央揃えの場合、Size To Content にチェックを付けるとレイアウトしやすいです。
タイマーの更新処理のところも、このWidgetの関数に置き換えます。
100以上の桁表示を作っていないので、99.99でカンストするようにしています。表示は見た目に止まりますが変数へのカウントアップは止めていないので、必要であればもう一つフラグを用意した方がよいかも。数字の桁を足す場合、 000.00 となるので、ゼロサプレスの処理が欲しくなる。この辺りは、ランキングの仕組みや、100秒を上回るのが当たり前のような難易度かどうかなどを考えると決まってくると思います。
で、寄り道で中断していたRetryボタンの処理の続きです。
変数を初期値に戻します。このあと難易度を上げるところで理由を書きますが、ここで StepCount の値を 1始まりではなく 0 にします。
あとは、出現イベントから始めれば、通常のゲームループに戻れるはずです。
そのためのカスタムイベントを作って、出現処理のところに脇からつなぎます。
このカスタムイベントを呼び出すのが、さきほどの ForEachLoop処理の Completeピンです。
これで大体できました。仕上げに難易度を上げる処理です。
その準備として、Integer型の配列変数をもう一つ追加します。
次に、先に作っていた NumberPool という Int型の配列も少し初期化の部分を変更します。Event Pre Construct の部分に、配列のサイズを設定するノードを挿入。
数字を初期化する関数を改造します。
まず、前回と同じく 1~25 までの数字で遊ぶ場合。
先に配列のサイズを決めているので、ここでは Addノードは使えません。代わりにSet Array Elem という、指定した 場所の内容を書き変えるノードを使います。
今回新しく追加したチェックのための配列をクリアしてから、シャッフルする前の状態を保存しておきます。このクリアは、すぐあとのコピーのために行っていて繰り返し遊ぶときに重要になります。上のようなシンプルなパターンでは、効果が薄いのですが、効果を発揮するのが次のパターン。
もっと難しくする場合。
1~99 までの 25個の数字で遊びます。まんべん無く数字が使われるようにしたかったので25枚目のやつだけループ処理が終わってから乱数をセットしています。
このパターンだと1~25のように パネルの番号とクリックの順番が一致しなくなるので、チェックしやすくするためシャッフルする前の状態が必要になります。
そこで、チェックのところが、下のように変わります。
配列から値を順番に0から取り出してチェックしてゆくので、変数StepCountをゼロ始まりに変更しています。
これで改造ポイント1~3完了です。
再生して数字の並びを確認してみます。
一番小さい数字からクリックしていくのですが、これが結構難しくて、なかなか30秒切れなかった。
ここからはおまけです。
上に貼った動画ですでに入ってますが、マウスのホバー処理とエフェクトを出してみます。
クリックしたときにエフェクトを出せないかと実験してみたけど、ParticleSysytemは、Screen描画してるWidgetよりも手前に描画できないようなので、とりあえず数字がヒットしたタイミングでプリセットの爆発エフェクトをSpawn してみたら派手で面白かったのでそのまま動画を撮りました。
Spawn Emitter at Locationを一つ追加するだけ。(雑い・・・)
再生時のカメラの視界に入るように座標を調整してるだけ。カメラが動くと当然ズレますが何か? WidgetをWorldに置くか、エフェクトをRenderTargetTextureにしてWidgetで利用するしかない感じ?
次はホバーエフェクト。当然タッチオペレーションだと無意味なやつです。マウスオペレーションならではですね。動画キャプチャにマウスカーソルが写り込まないので作ってみました。
そのための仕込みとして、色を付けるための Image をキャンバスに追加します。
カラーは数字の色に合わせて5色用意したいのですが、カラーごとにアニメーションを作るのはナンセンス。というわけで間に1枚専用のパーツを追加して、Render Opacity でアニメーションさせよう、って腹です。カラーは数字の色と同様に配列を用意します。型はLinearColor型。
(Font は SlateColor なのは何か理由があるのかな?地味に不便な気がする。)
この配列からカラーを取り出してセットする処理を 数字を受け取る関数に追加します。
このあと、マウスカーソルが乗った時、離れた時、のイベントを用意するのですが、その前に、マウスカーソルが離れたとき用のアニメーションを作っておきます。
RenderOpacity が追加されたことで、Colorのフェードを触らなくていいのが嬉しいです。この RenderOpacity の初期値は 0.0 にしておきます。
あとは、マウスイベントをOverrideします。
長いプルダウンリストから、 On Mouse Enter と On Mouse Leave を選択します。
On Mouse Leave は自身の上にマウスカーソルが乗ってる状態から、離れた瞬間に呼び出されるイベントです。
ただ再生するだけでOK。
一方、On Mouse Enter は自身の上に マウスカーソルが乗った(入った)瞬間に呼び出されるイベントです。ここでようやく Render Opacity が 1.0 になります。
このイベントが呼び出されたときに、アニメーションが残っている可能性があるので、強制的に止めるようにしています。
これで、カーソルが乗った瞬間に Render Opacity が 1.0 になって、カーソルがはなれたら、0.0に向かってアニメーションするようになります。
このくらいでいいかな~と思ったのですが、もう一つ思いついたので作ってみました。
数字の配列を作る関数をちょっといじります。
0~25までの 26個の数字を配列に入れるのですが、25個までと決めてあるので、この関数内だけで使えるローカル変数を使います。
26個の数字から、一つだけランダムで抜いて25個したら完成です。
次に、数字パネルのWidgetに手を加えます。
こんなマクロを用意します。
もうお分かりですね。アルファベットバージョンです。
しかも、大文字小文字が混在です。A~Z 26文字のうち、1文字だけ足りないので、ジジ抜きのような微妙な緊張感も一緒に楽しめるというやつです。
で、このマクロを無理やり↓挿しこみます。
どんな感じかというと、
ほどよい難易度でなかなか新鮮です。
いかがだったでしょうか。ひとまず今回の改造はここまでにしておきます。
始まりから終わりまで一つのゲームルールができると、いろいろアイデアも出やすい気がします。リザルト画面とかランキングとかネームエントリーとか作ると、どんどんアプリっぽくなっていきそうです。お手付きをカウントしたり一定の間隔以内だったらコンボボーナスとか。一定時間ごとに「急いで!」とか急かしてみたり。ヒント的にパネルが揺れたりしてもいいかもしれない。ベルトコンベアになってても面白そう。もうルールを変えて、何らかのペアをクリックして消しいくのもいいかもしれない。
イマドキのUE4のトレンドとは逆行してる気がしないではないけど、まぁ楽しんで作れるのが何よりも一番大事だと思う。
ではでは
ステキはパネルクリックライフを!