WASDで歩き、Spaceでジャンプするキャラクターができました。次はキーボードから手を離して、ゲームパッドでも同じ場所を歩いてみましょう。
Enhanced Inputでは、移動やジャンプの処理を使い回しながら、パッドの割り当てを追加できます。ただ、キャラクターが動けば完成というわけではありません。手を離したときに止まるか、メニューを開いた後もパッドだけで遊び続けられるかで、操作のしやすさが変わります。
この記事では、左スティックで歩き、ボタンで跳び、メニューを選んでゲームへ戻るところまで作ります。入力方式に応じた表示を作るための、Common Inputの使い方も最後に試します。
この記事でわかること
- 同じInput Actionへ、パッドのスティックとボタンを追加する方法
- 小さな入力を無視するDead Zoneと、その調整の考え方
- トリガーの押し込み量と、入力が成立する条件の違い
- メニューの最初の選択先と、ゲームへ戻す処理
同じ移動とジャンプへ、パッドを追加する
Enhanced Inputの入門で作ったBP_InputPracticeを使います。WASDで動き、Spaceで跳べる練習用の白いキャラクターです。運転モードへ切り替えていたら、徒歩へ戻してから試してください。
ここでは、Windowsで認識されるXbox系のパッド1台を例にします。ボタンの文字や接続方法は機種で異なります。まずOS側でパッドを認識していることを確認し、UEのPlay画面をクリックして入力先をゲームにします。
IMCへ2つの行を追加する
Playを止め、IMC_PlayerControlsへ次の割り当てを加えます。既存のWASDとSpaceは残します。
| Input Action | 追加するキー | 受け取る値 |
|---|---|---|
| IA_PracticeMove | Gamepad Left Thumbstick 2D-Axis | 左右のXと前後のY |
| IA_PracticeJump | Gamepad Face Button Bottom | 押した・押していない |
2D-Axisは、スティックの左右と上下をまとめて読む入力です。「Gamepad Left Thumbstick」の押し込みボタンや、X軸だけの入力とは別なので、キーの選択欄で末尾まで確認します。
パッドの新しい2行は、最初はModifiersとTriggersを空にします。スティックは初めからXとYを持つので、W/S用のSwizzleやA/S用のNegateをそのままコピーする必要はありません。
キーコンフィグの記事も進めた場合は、追加するパッドのジャンプ行のSetting BehaviorをIgnore Settingsにします。今回はその行をキー変更の対象にせず、キーボード側のJumpKeyを1枠のままにするためです。Space側のOverride SettingsとNameは変えません。

まず、歩いて跳んでみる
保存してPlayし、左スティックを前後左右へ倒します。入力のXは左右、Yは前後です。Enhanced Input入門で作ったAdd Movement Inputが、そのままこの値を受け取ります。
パッドの下側のフェイスボタンを押すと、IA_PracticeJumpからJumpが呼ばれます。Xbox系ならAです。キーコンフィグでSpaceをJへ変えていても、パッドの追加行から同じジ ャンプを呼べます。
変えたのは操作の入口です。歩く処理と跳ぶ処理は共通のまま、WASDとパッドの両方を使えるようになりました。
小さな入力をDead Zoneで整える
スティックは、手を離しても入力がぴったり0へ戻らないことがあります。その小さなずれが移動へ届くと、キャラクターがじりじり動きます。こうした、意図しない入力が残る状態をドリフトと呼びます。
Dead Zone(デッドゾーン)は、中央付近の小さな入力を0として扱う範囲です。「どれくらい倒したら動き始めるか」を調整するものと考えると、操作感との関係が分かりやすくなります。
1. 調整前の入力を見ておく
Play中にコンソールを開き、showdebug enhancedinput を実行します。コンソールは通常チルダキーで開きます。開けない配列では、「プロジェクト設定」→「Input」のConsole Keysへ、練習中に使っていないキーを設定できます。
表示されたIA_PracticeMoveの値を見ながら、スティックを倒し、中央へ戻します。キーボードには触れず、どの程度の入力が残るか確かめます。ここで見るのはUEへ届いた値で、パッド内部の生のセンサー値ではありません。
ドリフトが出ないパッドでも、少しだけ倒したときの反応を覚えておくと、設定後の違いを比べられます。
2. スティックの行へDead Zoneを加える
Playを止め、IMC_PlayerControlsのGamepad Left Thumbstick 2D-Axisの行にあるModifiersへDead Zoneを追加します。
| 項目 | 今回の値 | 意味 |
|---|---|---|
| Type | Radial | XとYを合わせた、中心からの距離で判定する |
| Lower Threshold | 0.2 | これより小さい入力を0として扱う |
| Upper Threshold | 1.0 | この大きさで出力が最大の1になる |
しきい値は、扱いを切り替える境目の数値です。Lowerは動き始める側、Upperは最大になる側の境目にあたります。Radialは円形に扱う方式で、XとYを別々に判定するAxialとは区別します。
IA全体へ付けると、同じIAを使うキーボードにも処理がかかります。今回はスティックの行へ付けることで、パッドだけを調整します。

3. 「止まる」と「少し動く」を両方確かめる
保存して再びPlayし、入力値と動きを比べます。たとえば入力の大きさが0.1なら、今回の設定後は0になります。一方、0.6の入力は0.5になります。0.2〜1.0の残った範囲を、出力の0〜1へ広げ直すためです。
Lowerを大きくするほど小さなずれを無視できますが、少しだけ倒して歩く操作もしにくくなります。0.2は調整の出発点です。手を離したときに止まり、意図した微操作もできる値を探します。
確認が終わったら、同じshowdebug enhancedinputをもう一度実行して表示を消します。入力が0なのに動き続ける場合は、Dead Zoneではなく 、移動処理や外から加わる力などを調べます。
トリガーは、押し込み量と成立条件を分ける
パッド背面のRT/LTなどは、どれくらい押したかを0〜1で読めるアナログトリガーです。軽く押すと小さい値、深く押すと1に近い値になります。
Enhanced InputにもTriggersという設定がありますが、こちらは「どんな入力なら操作を成立させるか」という条件です。パッドの部品としてのトリガーと、入力の成立条件は別のものです。

押し込み量を表示してみる
InputPracticeフォルダにIA_TriggerPracticeを作り、Value TypeをAxis1D (float)にします。IAのModifiersとTriggersは空にします。
IMC_PlayerControlsへIA_TriggerPracticeを追加し、キーはGamepad Right Trigger Axisを選びます。Axisの付かないボタン用の項目では、押し込み量を同じようには扱えません。
BP_InputPracticeへIA_TriggerPracticeのイベントを置きます。TriggeredからPrint Stringへ白い線をつなぎ、Action ValueをIn Stringへ接続してFloatからStringへの変換ノードを挟みます。Durationは0です。同じIA_TriggerPracticeイベントのCompletedからは、別のPrint Stringで0を2秒表示します。下の2図は、1つのイベントから出る配線を分けて示しています。

保存してPlayし、右トリガーを浅く、次に深く押します。離したときは0が表示されます。Completed側も用意すると、値の表示が消えただけなのか、入力が0へ戻ったのかを区別できます。

一定以上押した瞬間だけ反応させる
Playを止め、今度はIA_TriggerPracticeのTriggersへPressedを加え、Actuation Thresholdを0.5にします。TriggeredにつないだPrint StringのDurationは2へ変えます。
これで、0.5の境目に達する入力で1回反応する練習になります。浅く押してから深く押し、そのまま保持してみます。押し続けるだけでは表示が増えず、一度戻してから押し直すと、また反応します。
この設定ではCompletedを「物理的に離した瞬間」として扱えなくなるため、先ほどのCompleted→Print Stringの白い線は外します。Pressedは、成立の後に押し続けてもTriggered状態を維持しない条件だからです。

アクセルなら押し込み量を使い、1回の発射なら成立した瞬間を使う、という選び方になります。今回の例は入力を表示する実験なので、車や弾を作る処理は加えていません。
メニューを開いて、最初のボタンを選ぶ
キャラクターを動かせたら、次はメニューです。マウスはボタンを直接指せますが、パッドの十字キーは、今選んでいる場所から次へ移動します。
フォーカスは、決定ボタンを押したときに反応するUIの選択先です。マウスカーソルを動かすこととは別です。画面を開いた直後の選択先を決めておくと、パッドを持ったまま操作を続けられます。
ここでは「再開」と「操作を確認」の2ボタンを作ります。まずは画面の出入りを確かめるため、ゲーム時間を止めるポーズは加えません。
1. 2つのボタンを並べる
Widget Blueprintを作り、WBP_PadMenuと名付けます。DesignerでCanvas Panelの中央へVertical Boxを置き、幅400程度で次の部品を縦に並べます。
| 部品 | 名前 | 表示・設定 |
|---|---|---|
| Text | 見出し用 | メニュー |
| Button+Text | ResumeButton | 再開。Is Variable、Is Focusableをオン |
| Button +Text | HelpButton | 操作を確認。Is Variable、Is Focusableをオン |
| Text | HelpText | 最初は空欄。Is Variableをオン |
WBP_PadMenu自体もClass DefaultsでIs Focusableをオンにします。ボタン同士のNavigationは既定のまま、縦に並べた2つから始めます。UMGの基本操作はWidget Blueprint入門で確認できます。
練習中に選択先を見やすくするため、「プロジェクト設定」→「User Interface」のRender Focus RuleをAlwaysにします。フォーカスのある部品へ枠を描く設定です。

2. 最初のボタンを選ぶ関数を作る
WBP_PadMenuへ、入力も戻り値もない関数FocusFirstButtonを作ります。
関数の入口からSet User Focusへ白い線をつなぎます。TargetはDesignerのResumeButtonをGetで置いたもの、Player ControllerはGet Owning Playerです。
Set User Focusは「このプレイヤーの選択先を、この部品へ移す」という処理です。同名のEvent Reply用ノードではなく、TargetがWidget、入力にPlayer Controllerがあるものを使います。関数を作ったら、Widgetをコンパイルして保存します。

3. メニューボタンで画面を開く
InputPracticeフォルダへDigital (Bool)のIA_OpenPadMenuを作ります。Triggersは空にし、IMC_CommonでGamepad Special RightとキーボードのMに割り当てます。Xbox系ではMenu/Startにあたるボタンです。
BP_InputPracticeでIA_OpenPadMenuのStartedからCreate Widgetを呼びます。ClassはWBP_PadMenu、Owning PlayerはGet Player Controller(Player Index=0)です。
Return Valueを変数へ昇格し、PadMenuWidgetと名付けます。白い線は次の順に接続します。
- Create Widget → Set PadMenuWidget
- Add to Viewport(TargetはGet PadMenuWidget)
- Set Input Mode UI Only
- Set Show Mouse Cursor=true
- FocusFirstButton(TargetはGet PadMenuWidget)

UI OnlyのPlayer ControllerはGet Player Controller、In Widget to FocusはGet PadMenuWidgetです。Mouse Lock ModeはDo Not Lock、Flush Inputがある版ではオンにします。マウスカーソルのTargetも同じControllerです。

表示してから、最後に再開ボタンへフォーカスを渡します。 UI Onlyで入力先を画面へ向ける処理と、画面の中でどのボタンを選ぶかを決める処理を、この順に揃えます。

4. 確認ボタンと、戻る処理をつなぐ
WBP_PadMenuでHelpButtonのOn Clickedから、HelpTextをTargetにSet Textを呼び、左スティックで移動、Aでジャンプと表示します。

ResumeButtonのOn Clickedは、次の順です。
- Remove From Parent(Target=self)
- Set Input Mode Game Only(Player ControllerはGet Owning Player、Flush Inputはオン)
- Set Show Mouse Cursor=false(Targetは同じGet Owning Player)
画面を消すだけでは、入力先がUIのままです。Game Onlyでキャラクターを操作する状態へ戻すところまでつなぎます。

実践:パッドだけで操作を一周する
すべてコンパイルして保存し、Play画面をクリックします。ここからはマウスを触らずに試します。
- 左スティックで歩き、手を離して入力が止まるか確かめる
- Aを押してジャンプし、着地する
- Menu/Startを押す。「再開」にフォーカスの枠がある
- 十字キーの下で「操作を確認」へ移り、Aで決定する
- 操作説明が出る。メニューの後ろでキャラクターはジャンプしない
- 十字キーの上で「再開」へ戻り、Aで決定する
- 画面が閉じ、左スティックで再び歩ける

ここでは通常のUMG ButtonとWindowsの既定のUIナビゲーションを使っています。UIの決定を処理するために、IA_PracticeJumpへメニューの処理を追加する必要はありません。
Mキーでも開き、矢印キーとEnter、マウスのクリックでも同じ2ボタンを試せます。パッドへ切り替えた後も、元のキーボード操作が使えるかを確かめます。
今の入力方式をCommon Inputで調べる
パッドで遊んでいるのに「Mでメニュー」と出たままだと、どのボタンか迷います。表示を切り替えるには、入力方式を調べる処理と、表示を更新する処理をつなぎます。
Common Input Subsystemは、そのプレイヤーに使われている入力方式を扱う窓口です。Common UIプラグ インから使えます。まずはアイコンを用意せず、方式の名前をPrint Stringへ出して確かめましょう。
現在の方式を1回表示する
Playを止め、「編集」→「プラグイン」でCommon UIを有効にし、アセットを保存してエディタを再起動します。
BP_InputPracticeでGet Player Controller(0)からGet CommonInputSubsystemを置き、出力を変数CommonInputRefへ昇格します。BeginPlayの既存の準備処理の最後へSet CommonInputRefをつなぎます。

入力も戻り値もない関数PrintInputMethodを作ります。Get CommonInputRefからGet Current Input Typeを置き、返るEnumをStringへ変換してPrint StringのIn Stringへ渡します。白い線は関数の入口からPrint Stringへつなぎ、Durationは2です。
Enumは、決められた候補から1つを表す値です。ここではMouseAndKeyboard、Gamepad、Touchが主な候補です。Get Current Input Typeは値を読むノードなので、白い線は通しません。

Set CommonInputRefの後にIs Validを置いて変数を確認し、Is Valid側からPrintInputMethodを呼びます。Is Not Valid側はPrint StringでCommon Input unavailableと表示して終えます。
変わったときにも表示する
Get CommonInputRefからBind Event to On Input Method Changedを作ります。先ほどのIs Valid側を、Bind → PrintInputMethodの順へ組み替えます。

BindのEventピンから、対応するCustom Eventを作り、HandleInputMethodChangedと名付けます。赤い線で渡すデリゲートは、通知が来たときに呼ぶイベントを指定するものです。そのイベントの白い出力からPrintInputMethodを呼びます。通知には新しい方式の値も付きますが、今回は初回と同じ関数で現在の値を読み直します。

Bindは「変更があったら、この処理を呼んでほしい」と登録するものです。最初の1回と、変更された後の両方を表示することで、入力方式が変わるまで何も表示されない状態を避けられます。
保存してPlayし、キーボードを押した後にパッドを操作します。マウスを動かしたときも表示を比べます。パッドを挿しただけ、持っただけではなく、実際の操作に応じて方式 が変わることを確かめます。
表示の揺れを抑える仕組みなどもあるため、すべての物理入力が必ず即座に切り替え通知になるわけではありません。ボタンの絵を切り替える場合は、このPrintの代わりに、方式に合う文字や画像をWidgetへ設定します。
今回使うのは入力方式の取得と通知です。Common UIで画面の階層や決定・戻るの扱いまで組む場合は、Viewportや入力データなどの設定も含めて、公式のCommon UIガイドへ進みます。
うまく動かないときのチェック
| 症状 | 確認するところ |
|---|---|
| パッドがまったく反応しない | OSで認識されているか、Play画面が入力先か、IMC_PlayerControlsが有効か |
| スティックの押し込みでしか反応しない | キーがGamepad Left Thumbstick 2D-Axisか。押し込み用ボタンを選んでいないか |
| スティックから手を離しても動く | IAの値が残っているか。Dead Zoneはスティック行か、Lowerは手元のパッドに合うか |
| わずかに倒しても動かない | Lowerを大きくしすぎていないか。Dead ZoneをIAとIMCの両方へ重ねていないか |
| キーコンフィグの登録エラーが出る | 追加したパッドのJump行をIgnore Settingsにしたか。 キーボード側のJumpKeyは変更していないか |
| トリガーの値が0か1しかない | IAがAxis1Dか、キーがRight Trigger Axisか |
| メニューは出るが選べない | ボタンのIs Focusable、表示後のFocusFirstButton、Set User FocusのTargetとControllerを確認 |
| 閉じた後に歩けない | Game Onlyへ戻しているか。画面を消す処理だけで終わっていないか |
| Common Inputが見つからない | プラグインを有効にして再起動したか。Get Player Controllerから取得しているか |
おまけ:対応を広げるときの考え方
フォーカスの移動先を整える
2ボタンから設定画面やスクロール一覧へ広げると、「右を押したらどこへ行くか」「閉じた後はどこへ戻るか」も決める必要があります。UIのフォーカス管理で、Navigationの指定へ進めます。
ゲーム時間も止めたい場合は、ポーズメニューと組み合わせます。画面の表示、入力先、ゲーム時間をそれぞれ戻すことが大切です。
ボタンの位置と、印字された文字を分ける
Gamepad Face Button Bottomは、フェイスボタンの下側という位置を表します。ここではXbox系のAを例にしていますが、機種やプラットフォームで表示すべき文字や決定の慣習は異なります。
パッドの操作方式が分かることと、その機種に合ったアイコンを用意することも別の作業です。配信対象を決め、実際に使うパッドで表示と動作を合わせます。
パッドのキー変更と、2人プレイ
パッド側のボタンも変更可能にするなら、キーボードだけのJumpKeyとは別の登録名を使うか、Slotやデバイスを含めて変更対象を選びます。今回のIgnore Settingsは、最初の練習をキーボード1枠のまま続けるための選択です。
パッド2台で遊ぶ仕組みは、画面分割のローカルマルチプレイで扱います。プレイヤーごとのControllerや入力先へ広げる前に、1人分の操作を最後まで確かめておきましょう。
まとめ
パッド対応では、同じInput Actionへ入口を追加した後、スティックの小さな入力と、UIの選択先を整えます。
歩けることに加えて、手を離す、メニューを開く、選ぶ、閉じてまた歩くところまで試すと、操作の途切れる場所を見つけやすくなります。まずは手元の1台で、この一周を作ってみてください。
参考:Enhanced Input、Dead Zone、Pressed、Set User Focus、Common Input Subsystem、Common UI導入ガイド。