(第1回の記事:https://angelpinpoint.seesaa.net/article/518225887.html)
前提
・Unity 6000.2〜
・Unity Input System
・Windows 11
・ゲームパッド:エレコム JC-U4013SBK
スポンサーサイト
目次
・はじめに
・問題1: UI表示時、ゲームパッドで操作できない
・問題2: UI画面遷移時にフォーカスが失われる
・問題3: ゲームウィンドウ外からフォーカスが戻った時に操作不能
・問題4: シーンリロード後にボタン入力が再発生
・問題5: UI遷移時の効果音が初期表示でも鳴る
・問題6: 設定画面とゲーム入力の競合
・まとめ
はじめに
Unityで「Cat Tower」というゲームを開発した際、ゲームパッドかキーボードで遊べるようにしました。ゲームパッド(Aボタン、左スティック)とキーボード(スペース、矢印キー)の両方に対応しています。
- Cat Tower
- CatTower (Web版)
- Cat Tower (ダウンロード版)

今回は、Unity Input Systemを使って実現しました。
Unity Input Systemは、Unityの新しい入力システムで、従来の
Input.GetKey()を使う旧システムと比べ、ゲームパッドとキーボードの扱いが簡単になるそうです。ただ、私もゲームパッド対応は初めてだったこともあり、いくつか問題が発生したので、その問題と解決策をまとめておきます。
※ Unity Input Systemの基本的な使い方などの説明は割愛します。
問題1: UI表示時、ゲームパッドで操作できない
現象
タイトル画面や、ポーズメニュー表示時、ゲームオーバー時など、UIボタンを操作させたいとき、ゲームパッドでUIボタンを操作できない問題が発生しました。
原因
Unity Input SystemでUIを操作する場合、UIのいずれかの要素にフォーカスが当たっている必要があります。フォーカスがない状態では、ゲームパッドの入力がUIに伝わりません。
解決策
UI表示時に、明示的に初期フォーカスを設定します:
// タイトル画面のStartボタンに初期フォーカスを設定
private void SetInitialFocus()
{
if (startButton != null)
{
EventSystem.current.SetSelectedGameObject(startButton.gameObject);
startButton.Select();
}
}
ポイント:
・
EventSystem.SetSelectedGameObject()でフォーカス対象を設定・
.Select()で確実に選択状態にする(念のため)・UI画面表示時に必ず実行
問題2: UI画面遷移時にフォーカスが失われる
現象
ポーズメニューなどUI操作中に、設定画面などのダイアログを開き、再び戻った時にゲームパッドで操作できなくなる問題が発生しました。
原因
戻った時に、フォーカスが失われたまま元の画面に戻るため、操作不能になります。
解決策
ダイアログを表示する際に、直前のフォーカスを記憶しておいて、閉じる際に復元しました。
private GameObject previousSelectedButton;
public void ShowSettingsPanel()
{
// 現在のフォーカスを記憶
previousSelectedButton = EventSystem.current.currentSelectedGameObject;
settingsPanel.SetActive(true);
// 設定画面の最初のボタンにフォーカス
if (closeButton != null)
{
EventSystem.current.SetSelectedGameObject(closeButton.gameObject);
closeButton.Select();
}
}
public void HideSettingsPanel()
{
settingsPanel.SetActive(false);
// フォーカスを元に戻す
if (previousSelectedButton != null && previousSelectedButton.activeInHierarchy)
{
EventSystem.current.SetSelectedGameObject(previousSelectedButton);
}
}
ポイント:
・UI画面遷移時は必ずフォーカス管理を行う
・元の画面に戻る時は記憶したフォーカスを復元
問題3: ゲームウィンドウ外からフォーカスが戻った時に操作不能
現象
Alt+Tabなどで別ウィンドウに切り替えた後、ゲームに戻るとゲームパッドで操作できなくなる問題が発生しました。
原因
ゲームウィンドウがフォーカスを失うと、UIへのフォーカスが無くなっているため。
解決策
フォーカスのあるオブジェクトを記憶するようにしておいて、どこにもフォーカスが無い場合には直前までフォーカスがあったオブジェクトにフォーカスを復元します:
private GameObject lastSelectedGameObject;
void Update()
{
// 現在選択されているオブジェクトを記憶
if (EventSystem.current.currentSelectedGameObject != null)
{
lastSelectedGameObject = EventSystem.current.currentSelectedGameObject;
}
// フォーカスが外れた場合、直前のオブジェクトに戻す
if (EventSystem.current.currentSelectedGameObject == null)
{
EventSystem.current.SetSelectedGameObject(lastSelectedGameObject);
}
}
ポイント:
・Update()で常時監視
・フォーカスが外れたら自動復元
・ゲームウィンドウ外への切り替えにも対応
問題4: シーンリロード後にボタン入力が再発生
現象
ゲームオーバー後など、リトライボタンを押してシーンをリロードすると、リロード直後に再びボタン入力が発生してしまう問題がありました。これにより、ゲームが開始直後に意図しない動作をしてしまいます。
原因
シーンをリロードしても、ゲームパッドの入力状態がなぜか保持されたままになっていました。ボタンを押しっぱなしの状態でシーン遷移すると、新しいシーンでもその入力が残ってしまいます。その原因はよくわかっていません。
(実は、最初に疑ったのはゲームパッドの連射機能でしたが、連射機能をオフにしても発生しました…)
解決策
シーン開始時に、明示的にゲームパッドの入力状態をリセットします:
void Start()
{
// ゲームパッド入力をリセット
if (Gamepad.current != null)
InputSystem.ResetDevice(Gamepad.current);
// その他の初期化処理...
}
ポイント:
・
InputSystem.ResetDevice()で入力デバイスの状態をリセット・シーン開始時(Start())で実行
・Gamepad.currentがnullの場合も考慮
問題5: UI遷移時の効果音が初期表示でも鳴る
現象
UIボタンの選択を移動した際に効果音を付けたくて、HoverSoundというクラスを作り、UI選択時の処理を
ISelectHandlerで実装して効果音を鳴らすようにし、これを各ボタンにアタッチしたところ、UI画面の初回表示時にも勝手に効果音が鳴ってしまう問題が発生しました。原因
問題1や問題2でUI画面表示時に自動的にUIにフォーカスするようにしていたため。
そこで、UIボタン選択時ではなく別のボタンにフォーカスが移った時(
IDeselectHandler)に音を鳴らすように変更したところ、初期表示時の問題は解決しました。しかし、新たな問題が発生しました。
ボタンにフォーカスがある状態で設定画面を開くと、フォーカスが設定画面のボタンに移るため、元のボタンの
OnDeselectが発火して効果音が鳴ってしまいます。解決策
グローバルフラグで効果音を制御します:
// HoverSound.cs(各UIボタンにアタッチ)
public class HoverSound : MonoBehaviour, IDeselectHandler
{
public static bool GloballyEnabled = true;
public void OnDeselect(BaseEventData eventData)
{
if (GloballyEnabled && AudioManager.Instance != null)
{
AudioManager.Instance.PlayButtonHoverSound();
}
}
}
// UI画面表示時
public void ShowSettingsPanel()
{
HoverSound.GloballyEnabled = false; // 効果音を一時無効化
settingsPanel.SetActive(true);
if (closeButton != null)
{
EventSystem.current.SetSelectedGameObject(closeButton.gameObject);
closeButton.Select();
}
StartCoroutine(EnableHoverSoundDelayed());
}
IEnumerator EnableHoverSoundDelayed()
{
yield return new WaitForSecondsRealtime(0.1f);
HoverSound.GloballyEnabled = true;
}
ポイント:
・UI表示直後の効果音を無効化
・0.1秒後に再有効化
・
WaitForSecondsRealtimeでポーズ中でも動作問題6: 設定画面とゲーム入力の競合
現象
設定画面を開いている間も、ゲーム側の入力が有効になってしまい、意図しないゲーム操作が発生する可能性がありました。
解決策
ゲーム全体の入力を制御するフラグを用意:
// GameManager.cs
public bool CanReceiveInput => canReceiveInput;
private bool canReceiveInput = true;
public void ShowSettingsPanel()
{
canReceiveInput = false; // ゲーム入力を無効化
settingsPanel.SetActive(true);
}
public void HideSettingsPanel()
{
settingsPanel.SetActive(false);
StartCoroutine(EnableInputNextFrame());
}
IEnumerator EnableInputNextFrame()
{
yield return null; // 1フレーム待機
canReceiveInput = true;
}
// AcrobatCharacter.cs(ゲーム側)
void HandleJumpInput()
{
if (GameManager.Instance != null && !GameManager.Instance.CanReceiveInput)
{
return;
}
// ジャンプ処理...
}
まとめ
Unity Input Systemでゲームパッド対応を実装する際に発生した問題と解決策を紹介しました。
(1) UI表示時は必ず初期フォーカスを設定
(2) UI画面遷移時はフォーカスを記憶・復元
(3) ゲームウィンドウ外への切り替えに対応
(4) シーン遷移時は入力状態をリセット
(5) UI効果音は初期表示時を考慮
(6) ゲーム入力とUI入力を分離して管理
これらの対策により、Cat Towerではゲームパッドとキーボードの両方で操作できるようになりました。もっと良いやり方があるかもしれませんが。
完成したゲームはこちらです:
Cat Tower - 猫をジャンプさせて積み上げるゲーム
- CatTower (Web版)
- Cat Tower (ダウンロード版)

無料でプレイできますので、ぜひ遊んでみてください。
スポンサーサイト
【ゲーム開発の最新記事】