概要
例えばゲームパッド操作を前提として以下の様なUIを実装した際に、ボタン以外の箇所(藍色の背景部分など)をクリック/タッチすると、Button1に掛かっているフォーカスが外れてしまう。
※Canvasから「Graphic Raycaster」をRemoveしても判定が取られる上に、Bitbucketで公開されているソースの該当箇所を見た感じだと、その様な処理となっていたので不具合等では無く意図的な挙動かと思われる。
この仕様自体は「マウス/タッチ操作とキーボード/ゲームパッド操作に両対応しているゲーム」だったり「そもそもマウス/タッチ操作を行えない環境」であれば然程問題では無いと思われるが、例えばどちらも扱える環境で「ゲームパッド操作だけを前提としたゲーム」と言った物を作ろうとした際に、作りによっては誤ってクリック/タッチ判定が取られてしまうとボタンのフォーカスが消えて戻せなくなると言った問題が出てくる可能性がある。
どちらにせよ実装側で気をつければ回避出来そうな件ではあるが、今回は「そもそもこの仕様自体を回避することは出来ないか?」と思い、色々と調べてみたのでメモ。
※検証したUnityのバージョンは5.6.1p2
マウス/タッチ操作の無効化について
色々と情報を漁っていると下記のスライド及び気になる一文を発見。
-
プログラマがUnityでSTGを作った話
- 18ページ:「ControllerInputModuleをStandaloneInputModulenの代わりに使うことでマウス操作を無効化できる」
そこで早速記事中にリンクが貼ってあった ControllerInputModule を持ってきて解析及び実行してみた所、マウス/タッチ操作が完全に無効化されていることを確認。
一先ずは問題自体を回避する事は出来た。
ControllerInputModuleについて
中身を追ってみた所、物自体はデフォルトで用意されているStandaloneInputModuleから単純にマウス/タッチ関連の処理を削除した形の物だった。
※InputModule及びStandaloneInputModuleに付いてはドキュメントを参照
- 入力モジュール
-
Standalone Input Module
- ※StandaloneInputModule含めたInputModule関連のソースについてはBitbucketで公開されているソースから取得可能。
使い方としては簡単で、Hierarchy上にあるEventSystemオブジェクトに付いている"StandaloneInputModule"をRemoveするなりして、代わりにこちらをアタッチして有効にすれば良い。
※1点注意点として、ControllerInputModuleの元になったソース自体が古い為か一部APIの互換性と思われる所でエラーが出る箇所があったので、使用するにあたっては新しいAPIの方に置き換える必要があった。
「最新版の反映」及び「フラグ制御によるマウス/タッチ判定」を切り替えられるように設定してみた
上記の注意点にも記載しているが、ControllerInputModuleの元ソースが過去の物ベースとなっている為か、最新版と比べるとAPIの互換性の他にも処理に相違がある箇所が何点か見受けられた。
その上でマウス/タッチ操作自体も完全に削除されており、仮に「マウス/タッチ操作の有効/無効を切り替えられるようにしたい」といった場合にはStandaloneInputModuleを用いる必要があったので、自分の方で「最新版の反映」及び「フラグ制御によるマウス/タッチ切り替え」を対応したカスタムタイプのInpudModuleを作成してみた。
ソース自体はUnity5.6の物をベースとしているので、同じバージョン若しくは近いバージョンであれば動くはず。
※変更内容について、単純に内部処理で行われているマウス/タッチ判定の処理に対し、"m_EnableMouse"と言う値を見て切り分けを行うように変更を加えたのみ。下記に一部抜粋したものを記載。
public override void Process()
{
bool usedEvent = SendUpdateEventToSelectedObject();
if (eventSystem.sendNavigationEvents)
{
if (!usedEvent)
usedEvent |= SendMoveEventToSelectedObject();
if (!usedEvent)
SendSubmitEventToSelectedObject();
}
// ※以降がマウス/タッチ関連のイベントとなるので、ここで処理を切り分け
// →m_EnableMouseはInspector上からも設定可能
if (!m_EnableMouse) { return; }
// touch needs to take precedence because of the mouse emulation layer
if (!ProcessTouchEvents() && input.mousePresent)
ProcessMouseEvent();
}
ソース及びテストシーンはGitHubにアップしている。
※全体的に処理を見回してみた感じだと、マウス/タッチ判定自体は有効にしたままで、ボタン以外をクリックしてもフォーカスが外れない形のInputModuleとかも作れそうな気がしなくもなかったが一先ずはここまで。