🐸

【Unity】WebGLプラットフォームで端末の傾きを取得する

2021/03/05に公開

UnityのWebGLプラットフォームプロジェクトでスマホの傾き情報を取得してみました。

大前提

下記の通り、モバイル端末前提のUnity WebGL開発は推奨できません。それでもやってみたい、という方がいればこの記事を役立ててほしいです。

https://docs.unity3d.com/ja/2018.4/Manual/webgl-browsercompatibility.html

Unity WebGL コンテンツは現在モバイル端末ではサポートされていないことに注意してください。一部の機器、特にハイエンドなものでは動く場合もありますが、現在の大抵の端末は性能不足で Unity WebGL を十分に動かすだけのメモリがありません。そのため、モバイルブラウザー上でコンテンツを起動しようとすると、 Unity WebGL によって警告メッセージが表示される場合があります (この機能は必要に応じて無効にすることもできます)。

課題

Unity WebGL コンテンツは現在モバイル端末ではサポートされていないため、ネイティブアプリのようにUnityEngine.Input.compassで方角を取得することができません。
そのため、JavaScriptで端末の傾きを取得するスクリプトを作成しますが、JavaScriptで傾きを取得するためには以下の制約があります。

  • HTTPS通信であること
  • ユーザーに端末の傾き情報取得の許可を入力させること(iOS13以上のみ)

この記事には下記の通り、段階的に解決方法を記載します。

  1. JavaScriptで端末の傾き情報を取得し、Unityへ反映する
  2. HTTPS通信でモバイル端末から作成したWebGLアプリへアクセスする
  3. ユーザーに端末の傾き情報取得の許可を入力させる

環境

開発端末:Windows10
Unity:2020.1
モバイル端末:IPhone8 iOS13
ブラウザ:Chrome

課題1:JavaScriptで端末の傾き情報を取得し、Unityへ反映する

【Unity】WebGLプラットフォームでGPS情報を取得するで記載した方法と同じです。
Unityから提供されているブラウザースクリプトとの相互作用を利用します。

JavaScriptの実装

Unityプロジェクト内にAssets/Plugins/sample.jslib というファイルを作成しインポートします。
Unityから呼び出す関数を宣言します。今回は「WatchDeviceorientation」という関数を定義することにしました。

mergeInto(LibraryManager.library, {
  
  WatchDeviceorientation: function () {
    window.addEventListener("deviceorientation", function(event) { // ①
      xy = event.alpha + "," + event.beta + "," + event.gamma; // ②
      SendMessage('LocationManager', 'ShowRotation', xy); // ③
    });
  },  

});

① 傾きはdeviceorientationイベントを監視することで取得します。第二引数に傾きが検知された時のコールバック関数を渡します。
② Unityには1つのオブジェクトしか渡せないため、カンマ区切りで傾き情報を結合してます。
③ UnityのLocationManagerクラスのShowRotationメソッドを呼び出します。

Unityの実装

UnityではJavaScript関数の呼び出しと、取得した傾き情報を表示します。

using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class LocationManager : MonoBehaviour
{
    [SerializeField] Text RotationAlphaText;
    [SerializeField] Text RotationBetaText;
    [SerializeField] Text RotationGammaText;

    // JavaScript関数の宣言
    [DllImport("__Internal")]
    private static extern void WatchDeviceorientation();

    void Start()
    {
        // JavaScriptの呼び出し
        WatchDeviceorientation();
    }

    public void ShowRotation(String rotation)
    {
        string[] rotations = rotation.Split(',');

        RotationAlphaText.text = "alpha: " + rotations[0];
        RotationBetaText.text = "beta: " + rotations[1];
        RotationGammaText.text = "gamma: " + rotations[2];
    }
}

PCブラウザのモバイルエミュレータを使用すると挙動が確認できます。

課題2:HTTPS通信でモバイル端末から作成したWebGLアプリへアクセスする

【Unity】WebGLプラットフォームの動作確認を手軽にモバイル端末で実施するを参照してください。

ただしiOS13以上の端末を使用している場合は、この時点で閲覧しても傾きは表示されません。

課題3:ユーザーに端末の傾き情報取得の許可を入力させる

DeviceOrientationEvent.requestPermission()を用いてユーザーに傾き情報取得の可否をリクエストします。ユーザーにボタンを押してもらい、確認ダイアログを表示、という挙動にする必要があるため、WebGLとは別にHTMLのボタンを用意する必要があります(アラートで代替可能という記事もみましたが試してません。)。

ボタンを埋め込む

UnityのBuildで生成されたindex.htmlを以下のように編集します。
下記のように①~③の変更を加えました。

 <body>
    <!-- ①モーション許可のボタン追加 -->
    <button type="button" id="request_permission">モーションの許可</button><br>
    <div id="unity-container" class="unity-desktop">
      <canvas id="unity-canvas"></canvas>
	    
	<中略>
	    
              <div id="unity-build-title">Test_get_location_at_webgl</div>
      </div>
    </div>
    <script type="text/javascript">
	// ②ボタン押下時のアクションを追加
        document.getElementById("request_permission").addEventListener("click", function(){
          if (
            DeviceOrientationEvent &&
            DeviceOrientationEvent.requestPermission &&
            typeof DeviceOrientationEvent.requestPermission === 'function'
          ) {
            DeviceOrientationEvent.requestPermission();
          }
        })
    </script>
    <script>
      var buildUrl = "Build";
      var loaderUrl = buildUrl + "/build.loader.js";
	    
	<中略>
	    
	var fullscreenButton = document.querySelector("#unity-fullscreen-button");

      // ③モバイル端末でも全画面にならないようにif文を削除
      canvas.style.width = "600px";
      canvas.style.height = "900px";
      loadingBar.style.display = "block";
	    
	<中略>

この状態で、モバイル端末からアクセスし「モーションの許可」ボタンを押すと端末の傾き情報を取得できるようになりました。

Discussion