UE4_ウィジェットをゲームパッドでもキーボードでもマウスでも操作可能にする方法_最終章
ついにできた。
ゲームパッドでもキーボードでもマウスでも
操作できるように
してやったわ!!!!!!!!!!!!!!!!!!!!
様々なサイトの情報をブレンドして作ってやったわ!!!!!!!!!!!!!!!!!!!
さすがに今回は
他の人にも読んでもらえるように
丁寧に書いていく。
この記事の実装をするとできるようになること
・UE4のウィジェットで設定したボタンの配置が縦横の軸でかぶっていれば
マウスカーソルじゃなくても、キーボード、パッドからも操作可能になる
・選択中は不透明度1で、非選択中は不透明度0.5になる
・スペースやXBOXコントローラーのAボタンで決定になる
・フォーカス中のボタンから別のボタンに移動すると音が鳴る
※注意
・カーソルのホバー時に画像が変わったりする処理をボタンのアピアランスで設定できるけど、それは今回の処理を実装してもパッドからはできなかった。
・バージョンは4.25
・当方には知識皆無なので質問しないでください。
・あと参考にしたサイトは最後に書くとして
いじっていくゲームについては
udemyの講座で作ったゲームを基にしている
- ボタンを配置する
- レベルブループリントで操作有効化&フォーカス
- ウィジェットのイベントグラフで操作設定
- フォーカス外れたとき用の処理をレベルブループリントに書く
- わかりにくいが、こんな感じになるgif
- 参考にさせていただいたサイト
-
ボタンを配置する
ウィジェットでボタンを配置
レベルブループリントで表示処理
この辺は基本ですな。
-
レベルブループリントで操作有効化&フォーカス
レベルブループリントにこんなのを呼ぶ
いくつか種類があるが、今回はGameAndUIというものを配置。
説明は省く。
なぜか。
説明できないから。
( ^ω^)
いいからさっさとGetPlayerControllerをつなげよください。
あと操作を有効にした際に、最初にフォーカスするボタンを設定しておく。
ボタンはウィジェットからピンを引っ張ってGETすればいい。
検索にgetとボタンの名前入れたら多分出てくる。
このSetInput~(長い)は
イベントBeginPlayでウィジェットを設定した後につなげる(あたりまえ)
自分の場合は、このレベルのbeginplayの最後に置かないと
無限ループが発生して止まってしまう状態だった。
-
ウィジェットのイベントグラフで操作設定
※めちゃながい
変数を用意
先にウィジェットの中に変数「BeforeBtn」を用意しておく。
型は、ボタンの情報を入れるので
Buttonにする。
配列を作成し、ループさせる
ボタンを配列に格納する
配列って検索したら出てくる「配列を作成」に
getしてきたボタンをぶちこむ。
順番とかはお好みで。
配列なので上から順番に数字付けられる。
それをウィジェットのグラフ内のイベントtickとForEachLoopにつなぐ。
これでボタンの数だけ確認したり処理する流れができた。
ボタンを透明にしたり不透明にしたりする
SetRendetOpacityを2つ用意して、とりあえずターゲットにArrayElementをつなぐ
片方は0.5
もう片方は1.0にしておく。
あとはどういう時に不透明になればいいか処理を書くのだが
そもそもこの処理は自分が思い付きでやったもので
他の人の「音を鳴らす」という処理に付け足しただけ。
なので、その音を鳴らす処理を先に書く。
選択が変わったら、音を鳴らす
ここで、最初に作ったBeforBtnを使う。
要は「直前まで選んでいたボタン」という情報と一致しなかったら
それは選択をしているボタンを変えたことになるので
音を鳴らしてわかりやすくしよう
という意図。
なのでまず、
ブランチとHasKeyboardFocusをつなぐ。
このLoopから流れてくる処理は、ボタン一つに対しての処理なので
まずそれがフォーカスを持ってるのかどうか確認する。
持ってなかったら、そもそも見る必要ないのでFalseに流す。
直前のボタンと比べる
またブランチを置いて
NotEqualノードで、
変数のBeforeBtn、Loopから流れてくるボタン情報ArrayElementを比べる
こうなってるはず。
これでもしNotEqualが
「比べたけど一致しなかったよ(True)」を返せば
選択を変更した、ということがわかるので
あとは音を鳴らすだけ。
その前に、BeforeBtnに
今選んでいるボタンの情報をぶち込んで更新をしておかないといけない。
じゃないと、BeforeBtnで毎回比べるのに
直前に選んでいるボタンの情報がどこにもなくなってしまうから。
つなぐとこんな感じ。
音を鳴らす前に、BeforeBtnのセットにLoopのArrayElementをつなぐ。
音はウィジェットなので2Dでいいんでないかしら。
選ばれているボタンだった場合、不透明にする。
最後に、上の処理の中で、もしボタンが選ばれているボタンだった場合
最初の方に作った、不透明にするノード(InOpacityが1.0のSetRendetOpacityノード)を
つないでやる。
ここなら、「直前に選んだボタンと不一致」と不一致
つまり、選んでいるボタンかどうか判定していて
都合のいいことにFalseから流れてきたらその処理が適応できるから。
たぶん
こんな感じ。
以上でウィジェットのグラフいじりは終了。
疲れてもここで終わると、最後の処理の理屈が頭に入ってこないから
我慢してやって。
トイレはゆるす。
-
フォーカス外れたとき用の処理をレベルブループリントに書く
再びレベルブループリントに戻って(ウィジェットを出すレベルの)
先に出来上がりを載せる。
フォーカスが、何かの拍子に
ウィジェット内のどのボタンからも外れてしまった場合は
いくらキーボードやパッドをがちゃがちゃしても
フォーカスは戻ってきてくれないので
フォーカスが外れた場合は、指定したボタンにフォーカスを炊きなおす処理を入れる。
これはイベントTickにつないで、常に監視してもらうことになる。
フォーカスを復活させる処理を先に書く
ブランチのBooleanには、あとで処理をつなぐとして
まあそこに「おいおいフォーカスが無くなってるぜ」て返事を
送ればいいのだな
と思っておけばいい。
あとはイベントbeginplayに書いたものと一緒。
SetInputModeGameAndUIに
フォーカス復活時にフォーカスさせたいボタンを指定してやる。
ボタンの出し方忘れたら記事読み直してください。
あとは、すべてのボタンのフォーカスがされていない状態を
ANDでつなげてブランチのConditionに渡してやればいい。
フォーカスの状態はHasKeyboardFocus
それがNOTならTrueに流れる。
なんでそのままつなげてFalseにしないかというと
フォーカスが無い状態が、すべてのボタンであった場合
なので
そのままつなぐと、一つでもフォーカスが無くても発動してしまうことになるから。
レベルブループリント内に同じようなノードがいっぱいできてしまったので
自分はこんな風にならべて、できるだけ同じものからピンを引っ張るようにした。
最初にも言ったが
udemyの講座で作ったゲームを基にしているので
この記事で出てこなかったノードはその時に作ったもの。
人によっては設定が違うので
この方法では解決しないかもしれない。
わかりにくいが、こんな感じになるgif
画像の変更ができなかったので
カーソルの時とパッドの時で対応が違う。
まあ違いが判っていいかなって思ってる。