OculusGoでスクロールの入力に合わせFPS風の縦横移動を試みる

OculusGoを購入したので作成したFPSゲームをOculusGoでプレイしたいと思います。前回の記事では、縦横移動ができなかったので、今回はスクロールを検知して、縦横移動が出来るようにしてみたいと思います。

参考にしたウェブサイトは下記の2つです。

http://kan-kikuchi.hatenablog.com/entry/Oculus_Integration

Oculus Goのコントローラ入力の取得まとめ

まずは、Oculus Integrationというアセットをインストールすることが必要なようです。

インストールが終わると、エラーが29個くらい出ます。そこで、取り合えずいったんセーブしてからUnityを再起動しました。すると下記のウインドウが出てきます。

再起動してこのウインドウにYESを返すと、エラーが消えます。その代わりWARNINGがいくつか出ます。

Warningの1つにPackage missing for Virtual Reality SDK Oculus. Please add the Oculus (Standalone) package using the Package Manager Window.と出るので、その指示に従います。

パッケージマネージャーを開いてOculus(Standalone)を選択しインストールします。

これをインストールしたらWarningが消えました。

ところが、しばらくすると下記のエラーが復活。

error CS1503: Argument 1: cannot convert from 'method group' to 'Message.Callback'

グーグルで調べてみると、同じところで引っかかった人を発見しました。下記リンクが質疑の内容です。

How do I set up the OVR Avatar hands on a OVR Player Controller?

リンクによると、フォルダごと消せば大丈夫だったとの情報があったので、SocialStarterのフォルダごと消してみました。(一応バックアップは取っておきましたが。)

すると、見事にエラーが解決したので、理由は分かりませんが、当面はこれで良い事にします。

ビルドしてみると、何故かアプリのインストールがされません。

以下のエラーログを確認すると、OVRPlugin.aarにアクセスできないのが問題でビルド出来ないというような様子です。

Access to the path "Assets\Oculus\VR\Plugins\1.34.0\AndroidUniversal\OVRPlugin.aar" or "Temp\StagingArea\aar\OVRPlugin.aar" is denied.

ウェブサイトによってはOVRPlugin.aarをOVRPlugin.bakにすることで解決というものもありましたが、それではそもそもそのファイルが正しく使用できなくなるそうなので、根本的解決にはならないそうです。

[Solved] Can't Make Android Build - Access to OVRPlugin.aar Denied

上のリンクの掲示板によるとOVRPlugin Import Settingでアンドロイドに✔を入れると解決するとありますが、私の環境ではAndroidにはもともと✔が入っていたので、これも違いそうです。

元々Androidには✔が入っていた。

他のウェブサイトも当たってみた結果、読み込み専用にファイルがなってないか確認することとありました。しかし、私の環境では読み込み専用にはなっていませんでした。

[ANDROID] BUILDING FAILS WITH UNAUTHORIZEDACCESSEXCEPTION FOR OVRPLUGIN.AAR AFTER UPGRADING THE OCULUS UTILITIES PACKAGE

最終的に OVRPlugin Import Setting に全部✔を入れてどのプラットフォームもOKですよという状態にしたところ、このエラーは回避することが出来ました。

Oculus/VR/Plugins/1.34.0/AndroidUniversalのセッティング
AnyPlatform に✔を入れておく。

これですべてのエラーが解決され、Oculus Integrationインストール後、ビルドが正しくできるようになりました。ただし、このチェックボックスのチェックですが、ビルドするたびに何故か初期化されてしまうようなので、毎度✔を確認する必要がありました。注意が必要です。

ここで、やっとスクロールを検知するお話しにたどり着きます。スクロールボタンはデフォルトでは左右を見回すように割り当てられていました。本来であればマウスに対応するのがタッチパネルなので、正しい挙動だと思います。これを、強制的に横移動にしてあげたいというお話です。

すると、まずはFPSのキャラを動かしているスクリプトFirstPersonController.csをいじる必要があります。ざっと見てみるとHorizontalとVerticalを検知して、Vector2を作成している部分が見つかりました。これがキーボード操作の縦横キーに対応している部分になりそうです。これにスクロールを割り当てれば良いという事でしょうか。

private void GetInput(out float speed)
        {
            // Read input
            float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
            float vertical = CrossPlatformInputManager.GetAxis("Vertical");
            
            bool waswalking = _isWalking;

#if !MOBILE_INPUT
            // On standalone builds, walk/run speed is modified by a key press.
            // keep track of whether or not the character is walking or running
            _isWalking = !Input.GetKey(KeyCode.LeftShift);
#endif
            // set the desired speed to be walking or running
            speed = _isWalking ? walkSpeed : runSpeed;
           
            _input = new Vector2(horizontal, vertical);
            //以下省略

そこで、まず試してみたのは、OVRInput.Axis2D.PrimaryTouchpadを直接_inputに代入するという事です。

///ダメだったやつ
             //_input = new Vector2(horizontal, vertical);
             //この部分をコメントアウトして、タッチパネル入力を直接代入する。
             OVRInput.Update();
             Vector2 _input = OVRInput.Get(OVRInput.Axis2D.PrimaryTouchpad);
       //改変した部分

これで、ビルドしてみたのですが、相変わらずスクロールすると辺りを見回してしまいました。ここで、まずは、スクロール自体を切る方向で進めようと思いました。怪しい所を探してみるとRotateViewという関数があります。

private void RotateView()
        {
            //ココを全部コメントアウトしてみる
            Vector2 mouseInput = _mouseLook.Clamped(_yRotation, transform.localEulerAngles.y);

            /// handle the roation round the x axis on the camera

            _camera.transform.localEulerAngles = new Vector3(-mouseInput.y, _camera.transform.localEulerAngles.y,_camera.transform.localEulerAngles.z);
                                                    
            _yRotation = mouseInput.y;
            transform.localEulerAngles = new Vector3(0, mouseInput.x, 0);
            _cameraRefocus.GetFocusPoint();
        }

まずは、この内容を全部コメントアウトしてビルドしてみると、見事にスクロールしても見渡す動きは止める事ができました。ヘッドトラッキングで見渡すことはできるままでしたので、ヘッドトラッキングは別の所で上手く動いている様子です。ここで気付いたのは_mouseLook.Clamped(_yRotation, transform.localEulerAngles.y);という部分がマウスの動きを扱っている関数である可能性があるということです。ところが、探してみると、このファイルにはこの関数は使われていないという事が分かりました。

よって、別のファイルの関数を呼んでいるそうなので、色々探してみるとMouseLook.csというファイルを発見しました。そこには下記の様に書かれています。

namespace UnitySampleAssets.Characters.FirstPerson
{
    [Serializable]
    public class MouseLook
    {
        public float XSensitivity = 15f;
        public float YSensitivity = 15f;
        public float MinimumX = -360F;
        public float MaximumX = 360F;
        public float MinimumY = -90F;
        public float MaximumY = 90F;

        private float xvel = 0f;
        private float yvel = 0f;
        public bool smooth;
        public float smoothtime;


        public Vector2 UnClamped(float x, float y)
        {
            Vector2 value;
            value.x = y + CrossPlatformInputManager.GetAxis("Mouse X")*XSensitivity;
            value.y = x + CrossPlatformInputManager.GetAxis("Mouse Y")*YSensitivity;

            if (smooth)
            {
                value.x = Mathf.SmoothDamp(y, value.x, ref xvel, smoothtime);
                value.y = Mathf.SmoothDamp(x, value.y, ref yvel, smoothtime);
            }

            return value;
        }


        public Vector2 Clamped(float x, float y)
        {
            Vector2 value;
            value.x = y + CrossPlatformInputManager.GetAxis("Mouse X")*XSensitivity;
            value.y = x + CrossPlatformInputManager.GetAxis("Mouse Y")*YSensitivity;

            value.x = Mathf.Clamp(value.x, MinimumX, MaximumX);
            value.y = Mathf.Clamp(value.y, MinimumY, MaximumY);

            if (smooth)
            {
                value.x = Mathf.SmoothDamp(y, value.x, ref xvel, smoothtime);
                value.y = Mathf.SmoothDamp(x, value.y, ref yvel, smoothtime);
            }

            return value;
        }
    }
}

これによって、私はOculusのスクロールはマウスの入力を拾っているせいだという事に気付きます。crossPlatformInputManager.GetAxis("Mouse X")とcrossPlatformInputManager.GetAxis("Mouse Y")を、FirstPersonController.csの縦横移動の_inputに代入すれば良いと理解しました。

private void GetInput(out float speed)
        {
            // Read input
            float horizontal = CrossPlatformInputManager.GetAxis("Mouse X");
            float vertical = CrossPlatformInputManager.GetAxis("Mouse Y");
            
            bool waswalking = _isWalking;

これでビルドしてみると、スクロールするとちょっと前後左右に移動します。ただし左右の向きが進行方向と無関係だったり、移動距離が少しすぎたりするので、今後も調整や工夫が必要そうです。とりあえず、どこをいじればよいかが今回の検証で分かりました。今後はこの部分をヘッドトラッキングの方向に合わせて変更したり、距離を増幅させたり、というような処理が必要になってきそうです。ヘッドトラッキングの方向を取得するのはかなり難しそうなので、次の機会にリサーチしていこうと思います。

おすすめの記事