tanaka's Programming Memo

プログラミングについてのメモ。

【Unity6.x】WebGLのアプリをスマホでタッチ操作するためのInputSystemの設定方法

この記事は、Unity - Qiita Advent Calendar 2025 - Qiitaのシリーズ2の4日目の記事です。

11月に開催された技術書典19で、パズルゲームのステージの作り方を解説する趣味のゲーム開発:レベルデザイン編 パズルゲームのステージを作ろう!:アミューズワンという同人誌を出版しました。

techbookfest.org

この本の中で作成したステージを、実際に遊べるようにWebGLにビルドして、こちら(https://am1tanaka.github.io/VBirdHiyokoStageBook/digiga2025/index.html)で公開しています。

Unityは、WebGLビルドに力を入れていて、PCは当然のこと、スマホWebブラウザーでも結構動きます。これで、スマホでも手軽に遊んでもらえると思っていたのですが、公開してから、タッチ操作に対応していないことに気づきました。本記事は、その対応方法をまとめたものです。

目次

動作環境

動作環境は、次のとおりです。

  • Unity 6.0.58f2
  • Input System 1.14.2
    • InputActionにアクションを定義して利用

動かなかった原因

WebGLビルドしたものが、スマホWebブラウザー上でも動くようにできるだけ頑張ってはいますが、公式にはサポートされていません。ということで、油断してました。動作していない状態のInputActionは、次のとおりでした。

修正前のInputAction

ClickとPointとTapの3種類のアクションを定義しています。ClickとPointは、マウスのクリックとカーソル座標を取得するPC用の設定です。Tapが、Touchscreenを最初にタッチしたPrimary Touchを取得するスマホ用の設定です。

ここで問題となるのが、スマホWebブラウザーでは、TouchscreenのPositionは取得できるのですが、タッチ操作に対応していないようなのです。あれこれ調べてみると、Pointerで対応できるということでした。ということで、その方向で対応させます。

アクションごとの設定

アクションごとのAction TypeやInitial State Checkの設定は、次のとおりです。

  • Click
    • Action Type: Pass Through
    • Initial State Check: false
  • Point
    • Action Type: Pass Through
    • Initial State Check: true
  • Tap
    • Action Type: Pass Through
    • Initial State Check: false

Pass Throughってなんだっけという場合に備え(そうなった)、こちらの記事にしました。

Clickは、マウスがクリックされるか、WebGLの画面がタップされた時のperformedを使っています。startedやcanceledは使いません。また、マウスと画面タップの違いは気にしないので、最後に操作された入力が得られるPassThroughにしました。開始時に操作されているものは無視したいので、Initial State Checkは無効にしています。

Pointは、マウスの座標の読み取りのためのアクションです。マウスの座標は、デフォルト値が操作に影響せず、startedとcanceledの意味がありません。そのため、処理が軽いPassThroughを選択しました。Initial State Checkを有効にしているのは、開始時のマウス座標を報告してもらうためです。これにより、シーンが切り替わった直後のマウスの座標が取得できるので、最初からマウスカーソルを表示できます。

Tapの設定は、タッチスクリーンのみバインドしています。startedとcanceledは使っていないので、処理が軽いPassThroughにしました。有効になった時点でタッチしていても無効にしたいので、Initial State Checkは無効にしました。

解決策

あれこれ調査した結果、次の2手で解決できました。

  1. InputActionのClickに、PointerのPressを追加する
  2. 座標は、クリックやプレスを検出したときに、PointerのPositionを取得する

修正したInputAction

InputActionに、次のようにPointerのPressを追加しました。

修正後のInputAction

これで、タッチに反応するようにはなります。しかし、タップ座標がズレるという問題が起きます。座標の取得方法の改良が必要です。

タップ座標を取得する

座標の取得は、マウスとタッチで性質が異なります。マウスの場合、クリックをしていなくても、マウスカーソルの位置をPointアクションで受け取れます。その値を記録しておけば、クリックした座標として使えます。

ところが、Pointerの場合は、pressされるまで座標は分かりません。Pointアクションにpositionをバインドしていても、Clickアクションの時点では、その座標はまだ受け取れていません。そのため、マウスと同じ実装だと、前回にタッチした座標をタッチしたことになってしまいます。

これを解決するために、クリック時に、Pointerデバイスの座標を読み取って、現在の座標として使うことにしました。Clickアクションに登録するメソッドは、次のような感じです。

        void OnClickPerformed(InputAction.CallbackContext context)
        {
            if (context.ReadValueAsButton())
            {
                // 座標を更新
                currentPoint = Pointer.current.position.ReadValue();

                // クリック処理のユーザーメソッドの呼び出し
                Action(currentPoint);
            }
        }

まず、context.ReadValueAsButton()で、クリックした時であることを確認しています。ClickアクションはPass Throughなので、離した時にもperformedが呼び出されます。このif文で、離した処理を無視します。

Pointer.current.position.ReadValue()で、現在のPointerの座標を読み取って、マウスの現在の座標を代入しているcurrentPointに代入しています。

あとは、currentPointに対して行動させるためのユーザーメソッドであるAction(currentPoint)を呼び出しています。

InputActionのPointに、Pointer用の座標アクションを追加しなかったのは、このように座標をPress時に直に読み取るので、Pointer用の座標アクションが不要だからです。

以上で、対応が完了できました。

まとめ

UnityのWebGLビルドは優秀なので、スマホWebブラウザー上でも、かなりしっかりと動作します。ただ、InputSystemの扱いがスマホと異なるため、対応が必要でした。

スマホWebブラウザーでは、タッチ操作をPointerとして認識するので、Pointerの操作をバインドしました。今回は、タッチした座標が必要なだけなので、Clickアクションに、PointerのPressをバインドしました。座標は、Clickアクション内で、引数から読み取るようにしました。これで、サンプルゲームを、スマホでも遊べるようになりました。

am1tanaka.github.io

この記事は、Unity - Qiita Advent Calendar 2025 - Qiitaのシリーズ2の4日目の記事でした。