🐭

[Unity, InputSystem] 仮想マウスの実装で詰まった点

に公開

背景

現在 Unity で制作中のゲームでコントローラーからマウスを動かすために仮想マウスを実装する際に、日本語の情報があまり存在せず詰まってしまったので、問題点と解決方法を共有します。

基本的な仮想マウスの実装方法

InputSystem はVirtualMouseInputというクラスを提供しており、VirtualMouseコンポーネントを任意のオブジェクトにアタッチし、いくつかの設定をすることで簡単に仮想マウスを実装することができます。

基本的な仮想マウスの実装方法は以下の記事を参考にするのがいいと思います。
https://nekojara.city/unity-input-system-virtual-mouse

VirtualMouseInput の問題点

上の記事でも触れられていますが、公式が提供しているVirtualMouseInputクラスには以下のような問題点があります。

  1. CanvasScalerUI Scale ModeConstant Pixel以外の場合、仮想マウスの位置が正しく表示されない。

  2. 仮想マウスの有効/無効化が行えない。

  3. InputActionActionTypePassThroughにする必要がある。

問題点の解決方法

1. CanvasScalerUI Scale ModeConstant Pixel以外の場合、仮想マウスの位置が正しく表示されない。

この点はUnity のフォーラムでも議論されていた内容で、VirtualMouseInput内の座標を更新する部分を修正する必要があります。

以下に変更点を示します。

VirtualMouseInput.cs
@@ class VirtualMouseInput : MonoBehaviour
        private void UpdateMotion()
        {
+            // キャンバスを取得できていない場合はキャンバスを探す
+           if (m_Canvas == null)
+               TryFindCanvas();
            if (m_VirtualMouse == null)
                return;
@@ private void UpdateMotion()
            // Update software cursor transform, if any.
            if (m_CursorTransform != null &&
                (m_CursorMode == CursorMode.SoftwareCursor ||
                    (m_CursorMode == CursorMode.HardwareCursorIfAvailable && m_SystemMouse == null)))
-               m_CursorTransform.position = newPosition;
+               {
+                   // 仮想マウスのスクリーン座標をキャンバスのローカル座標に変換
+                   Vector2 localPos;
+                   RectTransformUtility.ScreenPointToLocalPointInRectangle(
+                       m_CursorTransform.parent as RectTransform,
+                       newPosition,
+                       m_Canvas.worldCamera,
+                       out localPos);
+                   m_CursorTransform.anchoredPosition = localPos;
+               }

また、この記事の最後に、私が実際に使用しているMyVirtualMouseInputクラスのコードを載せておきますので、参考にしてください。

2. 仮想マウスの有効/無効化が行えない。

この点も Unity のフォーラムで議論されていた内容で、色々なアプローチがあるようですが、いくつかの方法を試してもクリックやマウスホバーの判定が残ってしまっていました。
私は、VirtualMouseInputisActiveというフィールドを追加し、isActivefalseの時は仮想マウスの座標を-9999, -9999に固定するようにしました。

以下に変更点を示します。

VirtualMouseInput.cs
@@ class VirtualMouseInput : MonoBehaviour
+       public bool isActive = true;

@@ class VirtualMouseInput : MonoBehaviour
        private void UpdateMotion()
        {
+            // 無効状態なら画面外に固定して早期リターンする
+            if (!isActive)
+            {
+                Vector2 offScreenPos = new Vector2(-9999, -9999);
+                InputState.Change(m_VirtualMouse.position, offScreenPos);
+                if (m_CursorTransform != null)
+                    m_CursorTransform.anchoredPosition = offScreenPos;
+                return;
+            }

実際に使用する際は、VirtualMouseInputisActiveと、設定しているImageコンポーネントの表示/非表示を切り替えることで仮想マウスの有効/無効化を行うことができます。

3. InputActionActionTypePassThroughにする必要がある。

これは私の単純な確認不足で、VirtualMouseInputに渡すInputActionActionTypePassThroughにする必要があるようでした。
実際に、InputSystemを追加した際に自動生成されるInputActionAsset内の UI 関連のActionTypePassThroughになっていました。(新しいInputActionを作成するとValueになりますが)
この点の確認不足で仮想マウスをうまく動かすことができなかったので、困っている方は確認してみてください。

MyVirtualMouseInput の内容

以下が私が実際に使用しているMyVirtualMouseInputクラスのコードです。
このクラスを任意のオブジェクトにアタッチし、通常のVirtualMouseInputと同じように設定して下さい。

MyVirtualMouseInput.cs
GitHubで編集を提案

Discussion