続きの記事になります
前回の記事ではクイズゲームに必要な表示を、Widgetブループリントというアセットで用意しました。今回は全部を組み合わせて動くようにします。
目次
- その名をQuizGame
- タイトル画面からの遷移
- 確認してみる
- 流れをまとめると
- クイズの出題と回答ボタン
- バインドそして判定結果へ
- ブループリントインターフェイス
- で、そろそろアニメーション再生できるようにするか
- あとは、ボタンクリック対応
- まとめ
- 最後に
その名をQuizGame
仕上げというか材料を入れて煮込む鍋のような存在として、最後のWidgetブループリントを一つ追加します。名前を wb_QuizGame としました。
このWidgetブループリントは、ゲームを動かす要となるアセットになります。
今まで用意してきたものはパーツです。
さっそくキャンバスに、用意したWidgetを置いていきます。
まずは背景から。
Paletteタブ の User Created カテゴリに 作ったWidgetたちが並んでいます。
ここから wb_BG をキャンバスにドロップします。
こうやって、Widgetアセットは他のWidgetでも再利用できたりします。
最近Web界隈?で話題のアトミックデザインというやつが、UE4でも扱うことができます。ゲームUIの開発では修正や調整の効率化のためにいろいろ試行錯誤はしていて、『アセット開発』などという言葉が出てきたあたりから本格化した印象ですね。
余談はさておき
サイズがおかしいのでアンカーの設定を変更して拡げてやります。
画面いっぱいにします。
次に、Widget Switcher を取り出します。
Paletteタブ の Panelカテゴリにあります。
この Widget Switcher が事前に用意しておいた Widgetたちの器になります。
これも、上の背景(wb_BG)同様にアンカーで画面いっぱいまで拡げます。
まだ中身が無いので入れていきます。
Button の中に Text を入れたように ぽいぽいっとドロップします。
ただし順番が大事なので、今回は以下のように決めました。
① wb_Title (タイトル画面)
② wb_Main(クイズ画面)
③ wb_Right(正解演出)
④ wb_Wrong(誤答演出)
WidgetSwitcher が表示するのは常に1つ。それを番号で管理します。
そのために登録順が重要になってくるのです。
タイトル画面が表示されていればバッチリです。
WidgetSwitcher を選択した状態で Detailsタブ を見てみましょう。
Switcher というカテゴリに Active Widget Index というパラメータがあります。
ここを 0~3 の数字で変更してみてください。
数字を入力してEnterキーを押すと切り替わるのがわかります。
確認が済んだらタイトル画面からゲームを始めたいので 0 に戻しておきます。
ちょっと慣れないといけないのですが
プログラミングの世界では、番号を振って管理するものはたいてい
ゼロ始まり です。ゼロ番からナンバリングします。
なので、
① wb_Title (タイトル画面) → Index = 0
② wb_Main(クイズ画面) → Index = 1
③ wb_Right(正解演出) → Index = 2
④ wb_Wrong(誤答演出) → Index = 3
となっています。
ここでレイアウト作業は終了です。編集モードを Graph に変えましょう。
Designerモード同様に、エディタ左にあるリストから取り出します。
まずVariables タブから WidgetSwitcher を探してグラフにドロップします。
ドロップする際に、ちいさなポップアップが出るので、Get~ の方を選びます。
これが、『Getノード』のカタチです
このノードの右にある青い◎からドラッグします。
指を離したところでコンテキストメニューが出てくるので、上の検索フォームから active と入力します。
リアルタイムにフィルタリングされるので、
Set Active Widget Index を探して選択します。
これで、「WidgetSwitcher に対して、Active Widget Index の値をセットするよ」 という意味のつなぎ方ができました。
この方法だと、関連のある候補から選ぶことになるので、無関係なものをつないでエラーといった事態が避けられます。ぼくがブループリントをオススメするポイントの一つです。
この仕様は、ドラッグして指を離した際のポップアップにあるチェックボックスで切り替えができます。Context Sensitive(文脈依存)のスイッチです。
ここは有効のままにしておくのをオススメします。
このノードを、最初から並んでいる赤いノードにつないでみましょう。
ブループリントは同じ色の 〇同士をつなぐのが基本になります。
そして、白いホームベースの形同士をつないでようやくノードからノードへ処理の流れができあがります。
この赤い Event Pre Construction ノートは特殊なノードで、コンパイルしたときに実行されるイベントになります。
試しに、上の画像のように、Indexの値を 0以外 に変えて、エディタを Designer モードに切り替えたら、コンパイルしてみましょう。
WidgetSwitcherの表示が変わります。
WidgetSwitcherの切り替え方法をなんとなく実感できたところで、編集中断。いったん保存します。
タイトル画面からの遷移
次に、タイトル画面のWidgetブループリントを編集します。
ボタンをクリックしたときの挙動を作っていきます。
まずキャンバスに置いた Button を選択します。
エディタ右側 Detailsタブをスクロールした最下段にある、緑のボタン On Clicked をクリックします。
するとすぐさまエディタGraphモードに切り替わります。
新しくイベントノードが現れました。
これはクリックした際に呼び出されて実行されるイベントノードです。
カッコの中は配置した Button の名前です。Designer モードでいつでも変更できますが、今回は一つしかレイアウトしていないので、命名についてはひとまず放置します。
つぎにイベントディスパッチャーを作ってこのイベントにつなぎます。
エディタ左側から Event Dispatchers を探して、右にある + ボタンをクリックします。
ED_OnClicked と リネームしました。
これを、右のグラフにドラッグ&ドロップします。
指を離すと小さなポップアップが出るので、Call を選択します。
これを、On Clicked の赤いイベントノードとつなぎます。
これでクリックしたことを通知する仕組みが準備できました。
コンパイルして保存します。
QuizGameのWidgetを編集再開です。
先ほどの接続を切ります。
白い5角形を右クリックして Breake~ を選択するか、
白いラインの上で、Alt キーを押しながらクリックしても切断できます。
切れたら、エディタ左側に Variables というリストがあります。
そこに WidgetSwitcherに仕込んだWidgetたちが並んでいるので、さきほどイベントディスパッチャーを追加した wb_Title をグラフに取り出します。タイプは Get で。
ノードの右にある〇(出力ピン といいます)からドラッグしてノードを検索します。
今度は、 bind と入力。
そして、 Default > Bind Event to ED On Clicked を見つけて選択。
ここ似たようなやつが多いので慎重に。
このバインドノードと 赤い Event Pre Construction をつなぎます。
つぎに、バインドノードの左下にある、□ Event からドラッグしてカスタムイベントノードを取り出します。Add Custom Event を選択。
UE4は結構な数のイベントノードがあらかじめ用意されていますが、このカスタムイベントは、イベント処理を自由に作ることができる大変便利なノードです。
スタートボタンを押したときのふるまいをつくったので、PressStartButton と命名しました。
ノードの並びをちょっと整理しました。
WidgetSwitcher を切り替える Set Active Widget Index ノードの Index を 1 にします。
そろそろプレビューして確認してみます。
コンパイルして保存します。
確認してみる
実際に動くかどうか確認するには、再生する必要があります。
メインウィンドウのPlayボタンを押すか Altキーを押しながら P キーで今のレベル(見えている状態のワールド)がゲームプレイ状態になります。
今はまだ何も起こらないので、Widgetを表示できるようにします。
レベルブループリントを編集します。
メインウィンドウの上部にある Blueprints というボタンをクリックすると、プルダウンリストが出てくるので、 Open Level Blueprint を選択します。
グラフエディタが開きます。
新しくノードを取り出します。
何もないところで右クリックして Create widget を検索。
出てきたのはこんなノード ↓
Class のところに wb_QuizGame をセットします。
セットする方法は2種類。
プルダウンから検索する方法と、コンテンツブラウザでアセットを選択した状態で白い矢印をクリックする方法。
Return Value のピンからドラッグして、Add to Viewport ノードを取り出します。
初めから置いてある Event BeginPlay ノードとつなぎます。
これで準備完了、ではあるのですが、少しだけ安全対策を施しておこうと思います。
UE4 は UI のクリック対象ではない部分(例えばボタン以外)をクリックしてしまうと、背後のステージをクリックしたことになって、カメラをぐりぐり動かすことができるようになっています。そして、マウスカーソルが非表示にされてしまいます。フォーカスが移ってしまうんですね。
Shiftキー を押しながら F1 キーで戻ってきますが、慣れないと焦るので、今回はUI表示がメインの画面でもあるので、常時カーソルを表示するようにしてしまいましょう。
ノードを2つほど取り出してつなぐだけです。
まず何もないところをクリックして、Get Player Controller ノードを探します。
UE4触ってると、何かとお世話になるやつです。
次に ReturnValue から Set Show Mouse Cursor という変数を 取り出します。
いつもと様子の違うのが出てきました。
これは、 Player Contoroller が持っている変数に値を書き込もうとしています。
チェックをつけてつなぎます。
これで安心。
コンパイルして保存します。保存は初めてになると思うので、以下のようなダイアログが出てきます。
とりあえず Widgetフォルダと同じ階層に名前を付けて保存します。
保存できたら再生してみます。
STARTボタンをクリックして切り替われば・・・
バッチリです。
止めるのは Escキー か、 エディタ上部の Stopボタンです。
今回プロジェクトを新しく作っているので、UE4を起動すると基本の テンプレートレベルが開かれます。
引き続きこのレベルを使う場合は、毎回ダブルクリックして開くことになります。
最初から開いていてほしい場合は、Editメニューの Project Settings > Maps & Modes にある Default Maps で起動時のレベルを指定できます。
結構長くなってきた。
流れをまとめると
マウスのクリックを受け付けるWidget に イベントディスパッチャーを追加
▼
ボタンをクリックした際に、イベントディスパッチャーを呼び出す(Call)ことにする
▼
親のWidget は、 マウスのクリックを受け付けるWidgetに対して バインド(紐づけ)をする
▼
イベントディスパッチャーが呼ばれた(Call)ら、バインドしている親Widgetに通知が行って、つながっているカスタムイベントを処理する
ことになります。
イベントディスパッチャーは、バインドしてつながっている相手にだけ通知が渡ります。
自分からはバインドできません。される側になります。
なので、仕事の責任範囲が小さくできるぶん、作りが気楽にできます。
なんかあったらイベントディスパッチャー呼んどくか。あとは知らん。てな具合です。
他にも、
まだ親のほうで処理はつくられてないけど、将来的に必要って聞いてるから、イベントディスパッチャーを呼ぶとこを追加しておこう。というようなゆるい作りが可能です。
複数人で開発してる場合、
このタイトル画面Widgetのような場合、ボタンクリックとイベントディスパッチャー呼び出しのところを触らなければ、あとはお好きにどうぞ、とデザイナーにぶん投げることができます。ボタンの仕組みを変えたとしても、最終的にクリックした際にイベントディスパッチャーさえ呼ばれれば、あとは親が何とかします。または、この仮組みのようなWidgetをサクッと作ってプログラマに渡しておくと、ゲーム開発がスムーズになるのを少しは期待できます。
さてさて
WidgetSwitcherの切り替えもうまくいってるので、今度はメインの出題画面を仕上げます。
クイズの出題と回答ボタン
今回はチュートリアルということで、出題は固定の1問とします。
メインのWidgetを編集します。
Designerモードにしたら、出題用の Text を選択します。
そして右上にある Is Variable を有効にします。
最初から Is Variable が有効になっているものもありますが、Text については 無効になっているのが基本なので、必要に応じて チェックを付けます。
ついでに TextBlock_0 を TextBlock_Question にリネームしました。
Is Variable の状態は
Graphモードに変えるとどう変わったか判明します。
Is Variable を有効にすると言葉の通り、
Variables(変数)として扱うことができるようになります。
これを グラフに取り出します。Getタイプで。
そこへ、ドラッグして SetText(Text) ノードを探してやります。
この In Text ピンのところにテキストを入力できるので、問題文を入力してみます。
複数行にしたい場合はShiftキーを押しながらEnterキーで改行できます。
問題文を入力出来たら、 Event Construct につなぎます。
世界三大料理として挙げられる 中華料理 と
フランス料理 あと一つは?
Event Pre Construct と違うのは、コンパイルしても実行されない点です。ゲームが再生されたときに実行されます。
コンパイルした後、Designer モードに切り替えても Text Block となったままなのが確認できます。
確認のため再生してみましょう。
コンパイルして保存したら、Playボタンを押すか、Alt + P です。
Startボタンをクリックしたらちゃんと反映されてました。
次に回答ボタンを仕込んでいきます。
まずボタンの名前。
ただ配置しただけで放ってあったので名前を付けます。
そうすることでブループリントで扱う際にわかりやすくなります。
リネームの方法は2か所で変更できます。
エディタ左側のヒエラルキー内で右クリックして Rename を選ぶか、 F2キー
もう一か所は、Detailsタブの一番上
どちらで変更してもOK。
上から順番なのが分かるように、 0 1 2 3 とか A B C D 、1st 2nd 3rd 4th など連続するように名付けます。
続けて、Button の子供にした Text も内容を変更します。
この Text も Is Variable を有効にして、Button と同じように順番がわかるように名前を付けます。
最終的にヒエラルキーはこうなりました。今回 ABCD を採用。
これで、編集モードを Graphモードに移行します。
反復的な操作が増えてきたので、この辺から省略気味でいきます。
Variablesのリストに追加されているので、グラフに Getタイプでドロップしたら、
問題文同様に回答のテキストをセットします。
一応再生して確認しておきます。
よしよし大丈夫そう。
次に
回答ボタンを押したときに、反応できるように
OnClickedイベントと、イベントディスパッチャーを用意します。
OnClicked イベントは、 Detailsタブの一番下にある緑のボタンから作ると、編集モードが行ったり来たりして面倒なので、Graphモードで作成することにします。
まず Graphモードに切り替えて、Variablesリストにある回答用の Button~ を選択
すると、エディタ右側の Detailsタブのところに、緑のボタンが現れるので、ここからも On Clicked イベントを作成することができます。
スクロール動作が入りますが、編集モードが切り替わらないので、連続して操作するときにサクサク進んでいい感じです。
ここにイベントディスパッチャーを一つ用意してつなぐのですが、パラメータを追加したイベントディスパッチャーにします。
まずは +ボタンを押して追加します。名前を ED_Answer としました。
選択状態にしておいて、Details タブにある、Inputs の欄にある+ボタンをクリックします。パラメータの名前を Judgment としました。タイプは Boolean です。
このタイミングで、一度コンパイルします。
パラメータを追加したりパラメータ名を変えた場合はエンジン内での情報の更新が必要になるようで、グラフに取り出す前だとスルー出来ますが、取り出してからだと、エラーが出ます。
このイベントディスパッチャーをグラフに取り出します。
OnClicked イベントにつなぎます。
4番目が正解だったので、Judgmentのところのチェックボックス を True にします。
これでボタンをクリックしたときに、正解か不正解かという情報も一緒に伝えることができます。
これでこのWidgetブループリントは編集完了です。
コンパイルして保存します。
バインドそして判定結果へ
またQuizGameのWidgetを編集再開です。
子要素のWidgetに イベントディスパッチャーが追加されたので、バインドする必要が出てきました。
タイトル画面の切り替えと同じようにバインドしてやります。
出題画面のWidgetを Variables のリストから探してグラフにドロップします。
バインドするイベントディスパッチャーを探します。
タイトル画面遷移のバインドノードの次につなぎます。
カスタムイベントの名前は Result としました。
自動で、Judgmentのピンが追加されています。
こうやってイベントディスパッチャーから値が送られてくるのです。
確認のため、Print String ノードをつないで再生してみましょう。
何もないところで右クリックして検索します。
色の違うピン同士はつながらないのですが、キャスト(型変換)ノードを間に挟むことでつながることがあります。
よく利用するキャストは、自動で入れてくれるものが多いので助かります。
コンパイルして問題なければ再生してみましょう。
回答ボタンをいろいろ押すと、左上に true と false がどんどん下に向かって表示されます。一定時間が経つと消えます。
問題なければ、イベントディスパッチャーはうまく働いているようです。
グラフに戻ります。
確認が済んだので、PrintStringノードは消して、今度は Branch (ブランチ)ノードをつなぎます。
何もないところで右クリックして、bran で検索すると絞り込めます。
カスタムイベントと、つないでやります。
ブランチノードは何もないところで B キー を押しながらクリックしても取り出せます。
これは条件によって処理の流れを分岐させるノードです。
右に True と False の実行ピンがあるので、ここに WidgetSwitcher の切り替えを行うノードをつなぎます。
Index の値は、 WidgetSwitcherにセットした順番のWidgetを意味します。
① wb_Title (タイトル画面) → Index = 0
② wb_Main(クイズ画面) → Index = 1
③ wb_Right(正解演出) → Index = 2
④ wb_Wrong(誤答演出) → Index = 3
これで確認してみましょう。
コンパイルして再生します。
正解画面と不正解画面がうまく切り替わればバッチリです。
完成まであともう少し!
あと解決しなければいけない点は2つ。
- アニメーションが再生されない
- Nextボタンを押しても反応がない
2 はもう何度かやってきたのでイメージできると思います。
問題は 1 ですね
ブループリントインターフェイス
Widgetブループリントを作ったのと同じように、コンテンツブラウザの何もないところで右クリックして、 Blueprints > Blueprint Interface を選択します。
IF_QuizGame と命名。
ダブルクリックしてエディタを開きます。
右上を見てみると、名前を入力してほしくてウズウズしてる様子が伺えます。
ブループリントインターフェイスは、関数を登録するところです。
といっても名前だけの。
イベントディスパッチャーと少し雰囲気が似ていて、中身がないのだけれど、存在できて、呼び出しも可能。呼ばれても何もしないので何も起こらない。一応存在はしてるので、呼び出す処理は先に用意できるし、エラーが起きない。中身は別の場所でオーバーライドして利用することができる。
なんとも不思議な存在。
とりあえず名前を付けてあげましょう。
StartAnim
としておきます。
編集作業はそれだけです。
コンパイルして保存したら閉じましょう。
QuizGameのWidgetに戻ってちょっと確認してみます。
グラフ上で、StartAnim を検索してみると ありました。
さっそく取り出してみます。
イベントディスパッチャーの Call タイプと同じ封筒のアイコンが右上についています。
これを 先ほどの ブランチノードで分岐した最後につなぎます。
とにかく正解だろうが不正解だろうが、なんかわからないアニメーションを再生してよ、ということになります。
さて、だれに対して?
それっぽい関数ノードは見つかったけど、さすがに対象を決めないと、コンパイルエラーになります。
この場合、 正解または不正解のWidgetブループリントが対象です。
さてどちらか?
表示されてる方(アクティブな方)
どうやって調べる?
こういう時役に立つのが、 get って検索することです。
きっと WidgetSwitcherに Set Active Widget Index なんてノードがあるんだから、Get なんちゃらもあるはずです。
ありました get だけだと 大量に出てきたので、get act とするとビンゴ!
今アクティブになってるWidgetを教えてくれるノードです。
このReturn Value の青いピンを、StartAnimにつなげばよさそうです。
さっそくコンパイルして再生してみましょう。
・・・
はい。すみません。動くわけないですね。
でもコンパイルしてもエラーになりません。名前しかない関数なのに、アクティブなWidgetといっても、 wb_Right 、 wb_Wrong にはまだ StartAnimなんて関数はかけらも存在しないのに。
普通は対象アセットが持ってないものには、アクセスできませんし、そもそもつなぐことすらかなわないのです。
それをひとまずエラーにならずに済ませてしまうのが ブループリントインターフェイスなのです。
ちなみに上の間接的なつなぎ方を直接的につなぐとこうなります。
これでコンパイルしてもエラーにはなりません。編集の順番を無視できます。
直接対象につながずにget Active Widget ノードをオススメしたいのは、処理の流れさえおかしくならなければ、WidgetSwitcher の中身の順番が変わっても関係ない点。
いろんなアセットやブループリント触ってるといちいちIndexがどうなってるかなんて把握できないし、忘れがちなので、こういった「今アクティブなやつ」みたいにフワッとした指示の出し方は結構気楽でいいのです。
で、そろそろアニメーション再生できるようにするか
ということで、wb_Right と wb_Wrong を編集します。
ついでに、Nextボタンの対策も。
どちらも同じ内容なので、wb_Right をベースに書いていきます。
編集モードを Graphに切り替えると、 エディタ上部に Class Settings という大きなボタンがあります。
これをクリックすると Details タブの内容が変わります。
まん中付近に Interface というカテゴリがあるので、そこの Add ボタンを押して、今回用意した ブループリントインターフェイスを選択します。
と、同時に左のMyBlueprintタブにも Interfaces というカテゴリが出現します。
これ、ただのカタログのようなもので、グラフにドラッグできません。
なので、オーバーライドします。
すぐ上にある Functions カテゴリの右上に Override というボタンがあるのでクリックすると長いリストが出てきます。
その一番下に StartAnimがいるはずです。
選択すると グラフに イベントノードが出現しました。
ここに、作っておいたアニメーションを再生させる処理をつなぎます
まず Variables > Animations から IN をGetタイプで取り出して、
そこから
Play Animation ノードを探します。
イベントとつなげばOK。
あとは、ボタンクリック対応
イベントディスパッチャーを用意します。
タイトル画面の遷移と同じく特にややこしいこともしないので、ED_ButtonPressed とでもしておきましょうか。
On Clicked イベントを取り出して、イベントディスパッチャーとつないだら完成。
コンパイルして保存したら、不正解用のWidgetも同じ様に仕上げます。
流れを振りかえると
- ClassSettings の Interface に Add
- Functions の Overrideボタンから StartAnim をノードを取り出す
- そこにアニメーションを再生させるようにつなぐ
- OnClickedイベントを取り出す
- イベントディスパッチャーを追加してつなぐ
です。
最後の仕上げ
Nextボタンのバインドをするので、
また QuizGameのWidgetに戻ります。
正解、不正解の演出のあとは、再びクイズ出題画面に戻るようにします。
さて復習です。これをノーヒントでできるでしょうか?
ちょっと離れたところとつながってます。
ということで非情ながら次に進みます。
バインドした際に実行するカスタムイベントは、形態が同じなら共用できます。
パラメータがついたりして差異が生まれると共用はできなくなります。
これで、正解の時も不正解の時もおなじ処理ができます。
ノルマとかのUI表示があれば、別々にしてもいいし、回答ボタンの時のようにBooleanのパラメータを使って分岐させるのもありです。
このカスタムイベントに WidgetSwitcher の切り替えをつないだら完成です。
Index は 1 にしておきます。
コンパイルして問題なければ保存して再生します。
画面遷移が下のようにつながっているのが確認できれば完成です。
おつかれさまでした
さすがに長かったですね。このページだけで 12,000文字に届きそうです。
まとめ
今回作ったものの仕様
複数の画面レイアウトを、それぞれWidgetブループリントとして作成
WidgetSwitcher を使って切り替えて表示
それぞれのWidgetからの通知はイベントディスパッチャーで受取り
それぞれのWidgetへの指示はブループリントインターフェイスを使用
このチュートリアルの効果
基本的なUMGの編集方法がわかる
キャンバスに置いたものをブループリントで扱う方法が学べる
複数の画面を手軽にプレビューできる仕組みが実践できる
各画面ごとに対して、軽いインタラクションを組み込むことができるようになる
・・・
といいな
最後に
理解範囲もボリュームもいい感じだと思ってるんですけど、いかがでしょうか。
もうしばらくアレンジやら、小ネタとかの記事を公開していくつもりです。
少しでも UE4の UI制作に 興味を持ってもらえたら嬉しいです。
わかりにくいところや質問、ツッコミ等あれば、このブログのコメント機能かTwitterにてお気軽にどうぞ。
自宅でしかレスできないので反応速度に関しては気長モードでお願いします。
ではでは
ステキな UMGライフを!