ただひたすらにつよくなりたい

同人サークル「フォーマルハウト」のプログラマー兼モデラーが色々と覚えてつよくなりたい、そんなブログ

【UE4】SurpriseDungeonで使ったネタのメモ③UMGをキーボードで操作する

今回はUMGをキーボードで操作する方法について書いていこうと思います。

これも結構前からいろんなやり方を模索していて、

UE4自体にFocusとかの機能がちらほら見えるので

標準でもっといいアプローチがあるのかなー?と思いつつ

毎回違うやり方をしている気がします。

 

f:id:madponta:20170330002902j:plain

 

具体的に今回作成したのは画像下部のやつですね。

そもそもとして、UMGのメインの入力としてはマウスやタッチが想定されています。

しかし、今回作成したゲームのようにマウスを通常の操作で使用しない場合は

UIが表示されるたびにマウスで決定させるわけにもいかないため、

キーボードで操作できるようハンドリングしてあげる必要があります。 

 

さて、それではいつも通り続きから行ってみましょう~。

 

 

今回の実装方式としては、

①プレイヤーのコントローラーにイベントディスパッチャーを作成

②UMGを作成する際に①とカスタムイベントを紐付ける。

③UMGを表示している状態で入力された場合、

 通常の入力ではなくイベントディスパッチャーを呼び出す。

といった構成で実装しました。

それでは①のイベントディスパッチャーの作成から!

f:id:madponta:20170330003536j:plain

普通にPlayerControllerの子として作成したBPです。

左下の赤枠の箇所からイベントディスパッチャーを作成できるため、

ここから入力に応じた数のイベントディスパッチャーを作成しましょう。

今回ははい/いいえを選ぶ上下と、決定の3つなのでそのように作成します。

f:id:madponta:20170330003846j:plain

そもそもイベントディスパッチャーって何よ?という話ですが、

わかりやすく言うと、他のクラスのイベントと紐付けておけるスイッチのようなものです。

今回はその「他のクラス」として選択肢のUMGを紐付けるわけですね。

 

続けて②のUMGを作成していきます。

通常通り右クリックからUserInterface→WidgetBlueprintと作成し、

AddCustomEventからカスタムイベントを作成します。

そこに先程作成したプレイヤーコントローラーのクラスでインプットを作成します。

f:id:madponta:20170330004717j:plain

カスタムイベントを作成せずにConstructイベントでやってもいいのですが、

UMGのConstructは通常のコンストラクタと違い、

作成したタイミングではなくViewportにAddしたタイミングで呼ばれるため、

少しタイミングが制御しづらいです。

そのため、Constructでは表示用の処理(最初に表示する際にアニメーションを発火するとか)に使い、

データ自体は先にカスタムイベントで作成しておくのがいいかと思います。

あくまで個人的な考えに過ぎませんが・・・

 

さて、その後、カスタムイベントのインプットからノードを伸ばし、

先程作成したディスパッチャーの名前を入れていくとこんなのがでるはずです。

f:id:madponta:20170330005342j:plain

これはイベントディスパッチャーに対する操作のノードたちで、

Assign→イベントを作成し、割り当てる

BindEvent→イベントを割り当てる

Call→イベントディスパッチャーを呼び出す

UnbindAllEvents from→紐付けられているすべてのイベントを解除する

UnbindEvent from→紐付けられている(1つの)イベントを解除する

といった具合になります。

今回はイベントを作成し割り当てたいので、Assignを選びましょう。

f:id:madponta:20170330005640j:plain

するとこのように、バインドするノードと、それに紐付いたイベントが作成されます。

これを先程作成したイベントディスパッチャー全てに行い、

確認用にPrintStringをつなげます。

f:id:madponta:20170330010020j:plain

今回は作成されたイベントの名前をそのままにしていますが、

ちゃんと作る場合はしっかり名前を変更したほうがいいでしょう。

 

この状態で①のPlayerControllerに戻り、UMGを作成して確認してみます。

f:id:madponta:20170330010638j:plain

CreateWidgetで②のUMGを指定し、作成したカスタムイベントを呼び出します。

TargetPlayerControllerは作成した本人になるので、Selfを繋いでおきましょう。

最後に一応AddToViewPortしていますが、何も追加していなければ何も表示されないので、

あってもなくても大丈夫です。ただ何も表示しないってことはないと思うので、

普通は呼び出したほうがいいですね。

 確認用にキー入力からイベントディスパッチャーをコールします。

左下のイベントディスパッチャーをドラッグ&ドロップして、

Callを選択すると早いですね。

 この状態でWorldSettingsからPlayerControllerを①で作成したものに変更し、

PlayInEditorしてみます。

今回キーを設定したのは↑、↓、Enterなので適当に連打すると、

f:id:madponta:20170330011330j:plain

 しっかりUMGのイベントが呼ばれていますね!

 

最後に③ですが、これについてはゲームによって割りと事情が変わると思います。

SurpriseDungeonの場合はPlayerControllerにIsUMGFocusというboolを作成し、

1.UMGを作成したタイミングでそのboolをTrueにする

2.選択が完了したタイミングでboolはfalseに戻す

といった方式でやっていました。イメージ的には下記です。

f:id:madponta:20170330011808j:plain

これで①~③が完了し、後はUMGでのイベントなどに

しっかりとした処理を書けばUMGをキーボードから操作することができます!

 

ここから下はちょっとした小話です。

今回はキーの数だけイベントディスパッチャーを作成しました。

これひとつにまとめられないの?と思うかもしれませんが、実際できます。

イベントディスパッチャーは入力をつけられるので、下記のように呼ぶこともできます。

f:id:madponta:20170330012301j:plain

 

そうした場合、紐付けたイベントからもInputKeyが取得できるため、

 

f:id:madponta:20170330012601j:plain

 このように分岐で処理をさせることができます。

しかし、この方式には問題があります。

前提として、UE4にはActionMappingという機能がついています。

例えばJumpというActionを設定した場合、

そのJumpに紐づくのはスペースバー、↑、ゲームパッドのボタン1・・・

というように、一つのアクションに複数の入力を割り当てる機能です。

 

では今回のEnterとしてエンターキー、スペースバー、ゲームパッドのボタン1を使いたい、という場合にどうなるかというと、

最初に紹介した方法の場合はEnterアクションからEnterイベントディスパッチャーを呼ぶだけで終わります。

しかし、AnyKeyを使う方法の場合はすべてをIf文で書く必要があります。

一旦設定したのに、操作方法が変わってスペースバーじゃなくてShiftキーを使いたい

となった場合も、ActionMappingだけの修正で済むか、

それに加えIf文を修正するかという差分が生まれるため、

キーの数だけイベントディスパッチャーを作成するほうがいいかと思います。

もちろんゲームによるため、最適な方をお使いください。

 

少し長くなりましたが以上です!